buildo / react-components

Collection of general React components used in buildo projects.
http://react-components.buildo.io/
MIT License
157 stars 21 forks source link

The hitchhiker's guide to default props with TypeScript #1082

Closed gabro closed 7 years ago

gabro commented 7 years ago

1. Meet the types!

Every component with defaulted props defines 4 type aliases. For example, given a component named Foo

export type FooDefaultProps = { ... };
export type FooRequiredProps = { ... };
export type FooProps = FooRequiredProps & Partial<FooDefaultProps>;
type FooDefaultedProps = FooRequiredProps & FooDefaultProps; // Not exported

Guidelines:

NOTE names of these types will change slighly when we'll introduce namespaces, see #1083

2. Use static defaultProps

Define default props values as a static on the component class and make sure to explicitly annotate the type (so you can't forget a default).

E.g.

export default class Foo extends React.Component<FooProps> {
  static defaultProps: FooDefaultProps = {
    label: ''
  };
  // ...
}

Why? Because we want React to keep defaulting our props.

3. Cast when accessing

If you're accessing a props that has a default, apply a cast to this.props.

E.g.

render() {
  const { label } = this.props as FooDefaultedProps;
  return <div>{label}</div>;
}

Why? this.props is already of the correct type, because React defaulted the props for us, but TS doesn't know. TypeScript will enforce this 🎉

4. If you define a helper, call it defaultedProps()

If you find yourself casting a lot, define a helper property called defaultedProps() that does the casting once.

E.g.

defaultedProps = () => this.props as FooDefaultedProps;

onChange = (value) => {
  const { onWhatever } = this.defaultedProps();
  onWhatever(value);
};

render() {
  const { label } = this.defaultedProps();
  return <div>{label}</div>;
}