Kiss my default props

Typing defaultProps with TypeScript

Created on July 24, 2020.

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.

Next

What is ownership?

Previous

Push me