Kiss my default props

Typing defaultProps with TypeScript

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.