ESC

Type to search the knowledge base.

Typing React Props

Type component props with required/optional fields, children, unions for variants, and HTML attribute extension patterns.

beginner3 min read
  • typescript
  • typing-react

Props are the public API of a component. Good prop types catch misuse at the call site: wrong variant strings, missing handlers, invalid children. Bad prop types (any, loose index signatures) make React TypeScript pointless.

Docs: React TypeScript Cheatsheet, React components.

Basic props type

type UserCardProps = {
  name: string;
  bio?: string;
  onFollow?: () => void;
};

function UserCard({ name, bio, onFollow }: UserCardProps) {
  return (
    <article>
      <h2>{name}</h2>
      {bio ? <p>{bio}</p> : null}
      {onFollow ? (
        <button type="button" onClick={onFollow}>
          Follow
        </button>
      ) : null}
    </article>
  );
}

Optional props use ?. Don’t make everything optional “for flexibility.”

children

type PanelProps = {
  title: string;
  children: React.ReactNode;
};

function Panel({ title, children }: PanelProps) {
  return (
    <section>
      <h2>{title}</h2>
      {children}
    </section>
  );
}

ReactNode covers elements, strings, numbers, fragments, portals, arrays, null. Use ReactElement only when you require an actual element.

Variant unions

type ButtonProps = {
  variant?: 'primary' | 'secondary' | 'danger';
  size?: 'sm' | 'md' | 'lg';
  children: React.ReactNode;
  onClick?: () => void;
  disabled?: boolean;
  type?: 'button' | 'submit' | 'reset';
};

function Button({
  variant = 'primary',
  size = 'md',
  type = 'button',
  children,
  ...rest
}: ButtonProps) {
  return (
    <button type={type} data-variant={variant} data-size={size} {...rest}>
      {children}
    </button>
  );
}

See literal types.

Extending native element props

type TextFieldProps = {
  label: string;
  error?: string;
} & React.ComponentPropsWithoutRef<'input'>;

function TextField({ label, error, id, ...inputProps }: TextFieldProps) {
  const fieldId = id ?? inputProps.name;
  return (
    <div>
      <label htmlFor={fieldId}>{label}</label>
      <input id={fieldId} aria-invalid={Boolean(error)} {...inputProps} />
      {error ? <p role="alert">{error}</p> : null}
    </div>
  );
}

ComponentPropsWithoutRef<'input'> pulls native attributes; WithRef when you forward refs.

Discriminated props

type LinkButtonProps =
  | { as: 'a'; href: string; onClick?: never }
  | { as: 'button'; href?: never; onClick: () => void };

function LinkButton(props: LinkButtonProps & { children: React.ReactNode }) {
  if (props.as === 'a') {
    return <a href={props.href}>{props.children}</a>;
  }
  return (
    <button type="button" onClick={props.onClick}>
      {props.children}
    </button>
  );
}

FC or not?

// Older style
const Badge: React.FC<{ label: string }> = ({ label }) => <span>{label}</span>;

Modern preference: annotate props on a function declaration; avoid FC unless you want its implicit children behavior (which changed across versions). Explicit children is clearer.

Default props

Prefer default values in destructuring over Component.defaultProps (legacy for functions).

Footguns

  1. props: any — disable value of TS.
  2. Re-defining className/style poorly when extending HTML.
  3. React.FC + generics — awkward; use function declarations.
  4. Optional callback vs required — if the button is useless without onClick, require it.

Interview out-loud answer

“I type props as an object type or interface, use unions for variants, ReactNode for children, and ComponentPropsWithoutRef when wrapping native elements. Discriminated unions model mutually exclusive prop sets. I avoid any and prefer explicit children over relying on FC.”

Polymorphic as prop (sketch)

type BoxProps<T extends React.ElementType = 'div'> = {
  as?: T;
  children?: React.ReactNode;
} & Omit<React.ComponentPropsWithoutRef<T>, 'as' | 'children'>;

Polymorphic components are powerful and easy to mistype — add them when the design system truly needs them, not for one-off cases.

Further reading

Related guides