Support for defaultProps in JSX
TypeScript 2.9 and earlier didn’t leverage React defaultProps
declarations inside JSX components.Users would often have to declare properties optional and use non-null assertions inside of render
, or they’d use type-assertions to fix up the type of the component before exporting it.
TypeScript 3.0 adds supports a new type alias in the JSX
namespace called LibraryManagedAttributes
.This helper type defines a transformation on the component’s Props
type, before using to check a JSX expression targeting it; thus allowing customization like: how conflicts between provided props and inferred props are handled, how inferences are mapped, how optionality is handled, and how inferences from differing places should be combined.
In short using this general type, we can model React’s specific behavior for things like defaultProps
and, to some extent, propTypes
.
export interface Props {
name: string;
}
export class Greet extends React.Component<Props> {
render() {
const { name } = this.props;
return <div>Hello ${name.toUpperCase()}!</div>;
}
static defaultProps = { name: "world"};
}
// Type-checks! No type assertions needed!
let el = <Greet />
Caveats
Explicit types on defaultProps
The default-ed properties are inferred from the defaultProps
property type. If an explicit type annotation is added, e.g. static defaultProps: Partial<Props>;
the compiler will not be able to identify which properties have defaults (since the type of defaultProps
include all properties of Props
).
Use static defaultProps: Pick<Props, "name">;
as an explicit type annotation instead, or do not add a type annotation as done in the example above.
For stateless function components (SFCs) use ES2015 default initializers for SFCs:
function Greet({ name = "world" }: Props) {
return <div>Hello ${name.toUpperCase()}!</div>;
}
Changes to @types/React
Corresponding changes to add LibraryManagedAttributes
definition to the JSX
namespace in @types/React
are still needed.Keep in mind that there are some limitations.