2

I've been searching through many forums and articles and did not find any successful way to define an interface for a function component in React that has required properties which are defined in defaultProps without throwing a "property is missing" Typescript error.

I've tried to set a default value directly in props but it doesn't work either. Is there any way or it's unresolved issue in React and Typescript?

To see this problem in action, I've provided CodeSandbox project.

Edit misty-pine-rtdl8

type ButtonProps = {
  color: "white" | "green";
};

const Button: FunctionComponent<ButtonProps> = ({
  // First way to define default value
  color = "green",
  children
}) => <ButtonContainer>{children}</ButtonContainer>;

// Second way to define default value
Button.defaultProps = {
  color: "white"
} as Partial<ButtonProps>;

const ButtonContainer = styled.button<ButtonProps>`
  background-color: ${(props: ButtonProps) => props.color};
`;

const App: FunctionComponent = () => (
  <div className="App">
    <h1>Hello CodeSandbox</h1>
    <h2>Start editing to see some magic happen!</h2>
    {/* Here is an error */}
    <Button>hello world</Button>
  </div>
);
3
  • Can you give a code example? Commented Feb 13, 2020 at 17:15
  • @ford04 It's already in the question. The "Edit on CodeSandbox" button Commented Feb 13, 2020 at 17:18
  • 1
    oh, my ad-blocker did hide that 😊. Consider to paste the code here also, so the question remains valid, if the sandbox gets deleted. Commented Feb 13, 2020 at 17:23

2 Answers 2

2

Since color is the only property on the ButtonProps type, you can use Partial, which will set the properties of the type as optional:

const Button: FunctionComponent<Partial<ButtonProps>> = ({
  // First way to define default value
  color = "green",
  children
}) => <ButtonContainer>{children}</ButtonContainer>;

Here is a working demo.

Edit:

Following up on your comment, this is what I would recommend. We can remove the defaultProps, and use ButtonProps to define the typings for ButtonContainer. On the Button component, you may simply spread the remaining props into the child ButtonContainer.

type ButtonProps = {
  color: "white" | "green";
  fontSize: string;
};

const Button: FunctionComponent<Partial<ButtonProps>> = ({
  // First way to define default value
  children,
  ...styleProps
}) => <ButtonContainer {...styleProps}>{children}</ButtonContainer>;

const ButtonContainer = styled.button<ButtonProps>`
  background-color: ${(props: ButtonProps) => props.color};
  font-size: ${(props: ButtonProps) => props.fontSize};
`;

const App: FunctionComponent = () => (
  <div className="App">
    <h1>Hello CodeSandbox</h1>
    <h2>Start editing to see some magic happen!</h2>
    <Button color='green'>hello world</Button>
  </div>
);

Here is the updated demo.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you! And what should I do in case there was more properties?
That really depends! are they optional?
That's hard to tell. Imagine that you're building a styleguide. Button has for example 15 properties, 12 of them are optional. However you use most of them in styled-components and don't want to use non-null assertion operator because you know, they are defined in defaultProps
Sorry, I am a bit confused now. I am not sure if this is what you want to achieve, but it definitely allows you to set them as optional, without using the non-null assertion operator. I added an additional property on the props as a demo.
1

Change your ButtonProps like this

type ButtonProps = {
  color?: "white" | "green";
};

Making the color props optional. And then you can initialize it with a default value, just like you are doing.

const Button: FunctionComponent<ButtonProps> = ({
  // First way to define default value
  color = "green",
  children
}) => <ButtonContainer>{children}</ButtonContainer>;

Hope it helps!

1 Comment

Thank you for your answer. However, this is exactly what I've wanted to avoid. I don't want to use optional properties because then you have to use non-null assertion operator

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.