# 2. Export PropTypes for All Components

Date: 2020-06-17

## Status

Implemented

## Context

It's not unusual for a consumer of patchwork to write a wrapper for an existing component. Here's a contrived example:

```tsx
import React from 'react';
import { Button } from '@wealthsimple/patchwork';

export const SpecialButton = (props) => (
  <Specialness>
    <Button {...props} />
  </Specialness>
);
```

Or even more commonly,

```tsx
import React from 'react';
import styled from 'styled-components';
import { Button } from '@wealthsimple/patchwork';

export const SpecialButton = styled(Button)`
  border: dashed 20px;
`;
```

The nature of JSX and React is to encourage this type of compositional approach to UI.

However we run into problems when we try to make these wrappers type-safe.

### Undesirable alternative #1: repeat the types locally

One alternative is to redefine the types locally:

```tsx
// UNDESIRABLE - not DRY

import React, type { Node } from 'react';
import { Button } from '@wealthsimple/patchwork';

type SpecialButtonProps = {|
  onClick: () => void,
  children: Node,
|};
export const SpecialButton = (props: SpecialButtonProps) => (
  <Specialness>
    <Button {...props} />
  </Specialness>
);
```

```tsx
// UNDESIRABLE - not DRY

import React, { type Node, type ComponentType } from 'react';
import styled from 'styled-components';
import { Button } from '@wealthsimple/patchwork';

type SpecialButtonProps = {|
  onClick: () => void,
  children: Node,
|};
export const SpecialButton: ComponentType<SpecialButtonProps> = styled(Button)`
  border: dashed 20px;
`;
```

This is not DRY, and is prone to manual errors and drift as patchwork changes over time.

### Undesirable alternative #2: extract the types using ElementProps

Flow's react typedefs provide the `ElementProps` utility to extract props from a component:

```tsx
// UNDESIRABLE - will interfere with an eventual typescript port.
import React, { type ComponentType, type ElementProps } from 'react';
import styled from 'styled-components';
import { Button } from '@wealthsimple/patchwork';

export const SpecialButton: ComponentType<ElementProps<Button>> = styled(Button)`
  border: dashed 20px;
`;
```

However using this will make an eventual move to typescript more difficult. It's also not a well-known feature of flow's react typedefs and isn't very explicit about what it's doing.

## Decision

The proposed change is to adopt an API convention that exported patchwork components should always export export their proptype types as well.

```tsx
// button/button.proptypes.js
export type ButtonProps = {|
  onClick: () => void;
  children: Node;
|};
```

```tsx
// button/button.component.js
import type { ButtonProps } from './button.proptypes';

export const Button = (props: ButtonProps) => (...);
```

```tsx
// button/index.js
export * from './button.component';
export * from './button.proptypes';
```

This gives consumers of patchwork a path to typesafe composition:

```tsx
// DESIRABLE: proptypes are accessible to consumers via import

import React from 'react';
import { Button, type ButtonProps } from '@wealthsimple/patchwork';

export const SpecialButton = (props: ButtonProps) => (
  <Specialness>
    <Button {...props} />
  </Specialness>
);
```

```tsx
// DESIRABLE: proptypes are accessible to consumers via import

import React, { ComponentType } from 'react';
import styled from 'styled-components';
import { Button, type ButtonProps } from '@wealthsimple/patchwork';

export const SpecialButton: ComponentType<ButtonProps> = styled(Button)`
  border: dashed 20px;
`;
```

## Consequences

The patchwork component generator (`yarn generate component`) is already set up to export things this way, so new components are already following this convention.

In patchwork 22.2.0 we took a pass through all the old components and updated them to this convention as well. As long as people are using the generator to create new components this should not affect any patchwork implementer workflows.

Consumers already using the undesirable patterns above will not see any breakage but will be encouraged to clean up time permitting.
