Skip to content

Latest commit

 

History

History
132 lines (98 loc) · 3.73 KB

default-props.md

File metadata and controls

132 lines (98 loc) · 3.73 KB
id title
default_props
Typing defaultProps

Typing defaultProps

For TypeScript 3.0+, type inference should work, although some edge cases are still problematic. Just type your props like normal, except don't use React.FC.

// ////////////////
// function components
// ////////////////
type GreetProps = { age: number } & typeof defaultProps;
const defaultProps = {
  age: 21,
};

const Greet = (props: GreetProps) => {
  /*...*/
};
Greet.defaultProps = defaultProps;

For Class components, there are a couple ways to do it(including using the Pick utility type) but the recommendation is to "reverse" the props definition:

type GreetProps = typeof Greet.defaultProps & {
  age: number;
};

class Greet extends React.Component<GreetProps> {
  static defaultProps = {
    age: 21,
  };
  /*...*/
}

// Type-checks! No type assertions needed!
let el = <Greet age={3} />;
An alternative approach

As per this tweet, defaultProps will eventually be deprecated. You can check the discussions here:

The consensus is to use object default values.

// ////////////////
// function components
// ////////////////
type GreetProps = { age: number };

const Greet = ({ age = 21 }: GreetProps) => {
  /*...*/
};
// ////////////////
// class components
// ////////////////
type GreetProps =  {
  age?: number;
};

class Greet extends React.Component<GreetProps> {
  const { age = 21 } = this.props
  /*...*/
}

let el = <Greet age={3} />;
Why does React.FC break defaultProps?

You can check the discussions here:

This is just the current state and may be fixed in future.

TypeScript 2.9 and earlier

For TypeScript 2.9 and earlier, there's more than one way to do it, but this is the best advice we've yet seen:

type Props = Required<typeof MyComponent.defaultProps> & {
  /* additional props here */
};

export class MyComponent extends React.Component<Props> {
  static defaultProps = {
    foo: "foo",
  };
}

Our former recommendation used the Partial type feature in TypeScript, which means that the current interface will fulfill a partial version on the wrapped interface. In that way we can extend defaultProps without any changes in the types!

interface IMyComponentProps {
  firstProp?: string;
  secondProp: IPerson[];
}

export class MyComponent extends React.Component<IMyComponentProps> {
  public static defaultProps: Partial<IMyComponentProps> = {
    firstProp: "default",
  };
}

The problem with this approach is it causes complex issues with the type inference working with JSX.LibraryManagedAttributes. Basically it causes the compiler to think that when creating a JSX expression with that component, that all of its props are optional.

See commentary by @ferdaber here and here.

Something to add? File an issue.