We’ll use the Bootstrap Badge component as an example. According to the Typescript React cheatsheet, when we use Typescript > 3.0, we have to use type inference:
import React, { ReactNode } from "react";
import classNames from "classnames";
import { Variant } from "./Bootstrap";
const defaultProps = {
pill: false,
};
export type BadgeProps = {
children: ReactNode;
variant: Variant;
} & typeof defaultProps;
const BS_ROOT = "badge";
function Badge({ children, variant, pill }: BadgeProps): JSX.Element {
return (
<span
className={classNames(BS_ROOT, `${BS_ROOT}-${variant}`, {
[`${BS_ROOT}-pill`]: pill,
})}
>
{children}
</span>
);
}
Badge.defaultProps = defaultProps;
export default Badge;
But imho, this looses the clear distinction between your component’s required and optional props! I would rather have the following BadgeProps type:
export type BadgeProps = {
children: ReactNode;
variant: Variant;
pill?: boolean;
};
An alternative approach
What if we would just use object default values?
import React, { ReactNode } from "react";
import classNames from "classnames";
import { Variant } from "./Bootstrap";
export type BadgeProps = {
children: ReactNode;
variant: Variant;
pill?: boolean;
};
const BS_ROOT = "badge";
function Badge({ children, variant, pill = false }: BadgeProps): JSX.Element {
return (
<span
className={classNames(BS_ROOT, `${BS_ROOT}-${variant}`, {
[`${BS_ROOT}-pill`]: pill,
})}
>
{children}
</span>
);
}
export default Badge;
See easier and simpler (KISS) and not only that according to a tweet of Dan Abramov, defaultProps will be eventually deprecated for functional components.