I can't figure out how to set default property values for my components using Typescript.
This is the source code:
class PageState
{
}
export class PageProps
{
foo: string = "bar";
}
export class PageComponent extends React.Component<PageProps, PageState>
{
public render(): JSX.Element
{
return (
<span>Hello, world</span>
);
}
}
And when I try to use the component like this:
ReactDOM.render(<PageComponent />, document.getElementById("page"));
I get an error saying property foo
is missing. I want to use the default value. I've also tried to use static defaultProps = ...
inside the component, but it had no effect as I suspected.
src/typescript/main.tsx(8,17): error TS2324: Property 'foo' is missing in type 'IntrinsicAttributes & IntrinsicClassAttributes<PageComponent> & PageProps & { children?: ReactEle...'.
How can I use default property values? Many JS components my company uses rely on them and not using them is not a choice.
With Typescript 3.0 there is a new solution to this issue:
Note that for this to work you need a newer version of
@types/react
than16.4.6
. It works with16.4.11
.From a comment by @pamelus on the accepted answer:
Actually you can use Typescript's interface inheritance. The resulting code is only a little bit more verbose.
With Typescript 2.1+, use Partial < T > instead of making your interface properties optional.
Default props with class component
Using
static defaultProps
is correct. You should also be using interfaces, not classes, for the props and state.Update 2018/12/1: TypeScript has improved the type-checking related to
defaultProps
over time. Read on for latest and greatest usage down to older usages and issues.For TypeScript 3.0 and up
TypeScript specifically added support for
defaultProps
to make type-checking work how you'd expect. Example:Which can be rendered and compile without passing a
foo
attribute:Note that:
foo
is not marked optional (iefoo?: string
) even though it's not required as a JSX attribute. Marking as optional would mean that it could beundefined
, but in fact it never will beundefined
becausedefaultProps
provides a default value. Think of it similar to how you can mark a function parameter optional, or with a default value, but not both, yet both mean the call doesn't need to specify a value. TypeScript 3.0+ treatsdefaultProps
in a similar way, which is really cool for React users!defaultProps
has no explicit type annotation. It's type is inferred and used by the compiler to determine which JSX attributes are required. You could usedefaultProps: Pick<PageProps, "foo">
to ensuredefaultProps
matches a sub-set ofPageProps
. More on this caveat is explained here.@types/react
version16.4.11
to work properly.For TypeScript 2.1 until 3.0
Before TypeScript 3.0 implemented support for
defaultProps
you could still make use of it, and it worked 100% with React, but you'd have to mark props that have defaults as optional with?
. Example:Note that:
defaultProps
withPartial<>
so that it type-checks against your props, but you don't have to supply every required property with a default value, which makes no sense since required properties should never need a default.strictNullChecks
the value ofthis.props.foo
will bepossibly undefined
and require a non-null assertion (iethis.props.foo!
) or type-guard (ieif (this.props.foo) ...
) to removeundefined
. This is annoying since the default prop value means it actually will never be undefined, but TS didn't understand this flow. That's one of the main reasons TS 3.0 added explicit support fordefaultProps
.Before TypeScript 2.1
This works the same but you don't have
Partial
types, so just omitPartial<>
and either supply default values for all required props (even though those defaults will never be used) or omit the explicit type annotation completely.Default props with Stateless Functional Components
You can use
defaultProps
on function components as well, but you have to type your function to theStatelessComponent
interface so that TypeScript knows aboutdefaultProps
on the function:Note that you don't have to use
Partial<PageProps>
anywhere becauseStatelessComponent.defaultProps
is already specified as a partial in TS 2.1+.Another nice alternative (this is what I use) is to destructure your
props
parameters and assign default values directly:Then you don't need the
defaultProps
at all! Be aware that if you do providedefaultProps
on a function component it will take precedence over default parameter values, because React will always explicitly pass thedefaultProps
values (so the parameters are never undefined, thus the default parameter is never used.) So you'd use one or the other, not both.