'How to specify (optional) default props with TypeScript for stateless, functional React components?
I'm trying to create a stateless React component with optional props and defaultProps in Typescript (for a React Native project). This is trivial with vanilla JS, but I'm stumped as to how to achieve it in TypeScript.
With the following code:
import React, { Component } from 'react';
import { Text } from 'react-native';
interface TestProps {
title?: string,
name?: string
}
const defaultProps: TestProps = {
title: 'Mr',
name: 'McGee'
}
const Test = (props = defaultProps) => (
<Text>
{props.title} {props.name}
</Text>
);
export default Test;
Calling <Test title="Sir" name="Lancelot" />
renders "Sir Lancelot" as expected, but <Test />
results in nothing, when it should output
"Mr McGee".
Any help is greatly appreciated.
Solution 1:[1]
Here's a similar question with an answer: React with TypeScript - define defaultProps in stateless function
import React, { Component } from 'react';
import { Text } from 'react-native';
interface TestProps {
title?: string,
name?: string
}
const defaultProps: TestProps = {
title: 'Mr',
name: 'McGee'
}
const Test: React.SFC<TestProps> = (props) => (
<Text>
{props.title} {props.name}
</Text>
);
Test.defaultProps = defaultProps;
export default Test;
Solution 2:[2]
I've found the easiest method is to use optional arguments. Note that defaultProps will eventually be deprecated on functional components.
Example:
interface TestProps {
title?: string;
name?: string;
}
const Test = ({title = 'Mr', name = 'McGee'}: TestProps) => {
return (
<p>
{title} {name}
</p>
);
}
Solution 3:[3]
Here's how I like to do it:
type TestProps = { foo: Foo } & DefaultProps
type DefaultProps = Partial<typeof defaultProps>
const defaultProps = {
title: 'Mr',
name: 'McGee'
}
const Test = (props: Props) => {
props = {...defaultProps, ...props}
return (
<Text>
{props.title} {props.name}
</Text>
)
}
export default Test
Solution 4:[4]
Adding my solution to the pot, I think it adds an additional level of readability and elegance onto the existing solutions.
Let's say you have a component MyComponent
with a mix of required and optional props. We can separate these required and optional props into two interfaces, combining them for the full prop interface of the component, but only using the optional one to set the default props:
import * as React from "react";
// Required props
interface IMyComponentRequiredProps {
title: string;
}
// Optional props
interface IMyComponentOptionalProps {
color: string;
fontSize: number;
}
// Combine required and optional props to build the full prop interface
interface IMyComponentProps
extends IMyComponentRequiredProps,
IMyComponentOptionalProps {}
// Use the optional prop interface to define the default props
const defaultProps: IMyComponentOptionalProps = {
color: "red",
fontSize: 40,
};
// Use the full props within the actual component
const MyComponent = (props: IMyComponentProps) => {
const { title, color, fontSize } = props;
return <h1 style={{ color, fontSize }}>{title}</h1>;
};
// Be sure to set the default props
MyComponent.defaultProps = defaultProps;
export default MyComponent;
Solution 5:[5]
I might be wrong, but passing the a default prop value on the function as the second voted reply says could lead to subtle bugs or over executed useEffects (I don't have enough rep to reply there, so here's a reproducible codesanbox)
Even if it's a really contrived example, and probably in most of the cases just bad component design, I have seen this more than once, even breaking full pages.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Community |
Solution 2 | |
Solution 3 | Barazu |
Solution 4 | fullStackChris |
Solution 5 | Frank Simon |