How to set default props to required props in functional components?

Viewed 1409

In Typescript, I set up a component as follows:

interface MyComponentProps {
  type: 'round' | 'square';
}

const MyComponent: FC<MyComponentProps> = ({type = 'round'}) => {
  return (
    <div />
  );
};

The type prop is required and has a default set in the component definition, but still I get and error when calling the component:

<MyComponent />
// Property 'type' is missing in type '{ }' but required in type 'MyComponentProps'.

Setting the property type to an optional type? solves the problem by implicitly changing the type to 'round' | 'square' | undefined but I don't want the property to be possibly undefined, because that would cause issues and weird code down the line where I must consider type being undefined at every point.

What do I want to happen?

I want 'type' to have a default value when not passed, but not be defined as undefined (i.e. optional).

What have I tried?

I tried adding

MyComponent.defaultProps = {
  type: 'round'
};

But this didn't help at all, and also I know that defaultProps are about to become deprecated for functional components anyway.

3 Answers

if you want to pass default value that means value is not mandatory. if value will not come then you have default value.

Update for typescript@4.4

Since ts@4.4 you can define such a type without explicit type assertion when exactOptionalPropertyTypes flag is set:

type MyComponentProps = {
  type: 'round' | 'square';
} | {
  type?: never
}

const MyComponent = ({type = 'round'}: MyComponentProps) => {
  return (
    <div />
  );
}

const NoProps = <MyComponent />
const UndefProp = <MyComponent type={undefined} /> // error
const WithProp = <MyComponent type="round" />

playground link

Unfortunatelly TS playground does not support storing exactOptionalPropertyTypes flag in the url yet. So you'll have to go into TS Config and set it manually.


I believe you cannot get what you want with straighforward typescript features. But massaging your types a bit with type assertion you can get pretty close:

interface MyComponentProps {
  type: 'round' | 'square';
}

const MyComponent = (({type = 'round'}: MyComponentProps) => {
  return (
    <div />
  );
}) as React.FC<MyComponentProps | {}>

const NoProps = <MyComponent />
const UndefProp = <MyComponent type={undefined} /> // error
const WithProp = <MyComponent type="round" />

playground link

I suggest you try followings this:

interface MyComponentProps {
  type?: 'round' | 'square';
}

const defaultProps: MyComponentProps = {
  type: 'round'
};

const MyComponent: FC<MyComponentProps> = ({type}) => {
  return (
    <div />
  );
};

MyComponent.defaultProps = defaultProps;
Related