Skip to content

TypeScript Props

Well-typed props document component APIs and catch misuse at compile time. This lesson covers optional props, children typing, extending HTML attributes, and advanced prop patterns.

Prop Type Patterns

Define an interface for each component's props. Mark optional fields with ?. Use union types for variant props: variant: 'primary' | 'secondary'.

Extend native element props: ButtonProps extends React.ComponentProps<'button'> spreads standard button attributes.

interface ButtonProps extends React.ComponentProps<'button'> {
  variant?: 'primary' | 'secondary';
  loading?: boolean;
}

function Button({ variant = 'primary', loading, children, ...rest }: ButtonProps) {
  return (
    <button className={variant} disabled={loading || rest.disabled} {...rest}>
      {loading ? 'Loading…' : children}
    </button>
  );
}

ComponentProps<'button'> includes onClick, disabled, type, etc.

Advanced Prop Types

// Discriminated union
type Props =
  | { mode: 'edit'; onSave: (v: string) => void }
  | { mode: 'view' };

// Pick/Omit from domain type
type UserCardProps = Pick<User, 'name' | 'avatar'>;
  • Use discriminated unions when prop combinations are mutually exclusive.
  • React.ComponentPropsWithoutRef<'div'> excludes ref for wrappers.
  • Export prop interfaces for consumers and Storybook.
  • Avoid optional everything — required props document essentials.

Props Typing Reference

Common TypeScript utilities for props.

Utility Use
ComponentProps<'input'> Extend native element props
ReactNode Type children
? optional Optional prop
Discriminated union Mode-specific props
Pick / Omit Subset of domain types
as const Literal variant types

Polymorphic as Prop

Components that render as different elements (as="a" vs button) need generic typing — libraries like Radix use complex generics; start simple with union as: 'button' | 'a'.

Safe Prop Spreading

Omit custom props before spreading rest to DOM to avoid React unknown prop warnings.

const { variant, ...domProps } = props;
return <button {...domProps} />;

Common Mistakes

  • Not extending native props on wrapper components.
  • Using any for children or event handlers.
  • Optional props without defaults causing undefined bugs.
  • Overly complex generics for simple components.

Key Takeaways

  • Interface per component documents the public API.
  • Extend ComponentProps for HTML wrapper components.
  • Discriminated unions model variant-specific props.
  • Omit custom props before DOM spread.

Pro Tip

Export props interfaces as export type ButtonProps — consumers import types without importing the component.