Skip to content

TypeScript Conversion Guide

Mike Turley edited this page May 30, 2019 · 9 revisions

Conversion Guide

Converting a component to TypeScript has multiple steps. There's a helper script react-core/scripts/convertComponentToTS.js to help with the tedious parts. Backup the JS for a component and then run node scripts/convertComponentToTS.js src/components/Alert and pull up the TSX/JS side-by-side to begin.

Converting a Class

Converting a class has a lot of caveats.

Prop Types

When converting PatternFly components to TypeScript, you'll need to specify a type for the interface as follows:

export interface LabelProps {
  children: React.ReactNode;
  className?: string;
  isCompact?: boolean;
}

Oftentimes we spread props to an HTML element like <div {...props}>. In that case have the props extend types in node_modules/typescript/lib/lib.dom.d.ts like so:

export interface LabelProps extends React.HTMLProps<HTMLDivElement> ...

In some cases, you will need to avoid duplicating a type specified in HTMLWhateverElement. You can use Omit for this purpose. In the example below, size is omitted from the inherited type HTMLHeadingElement so we can use our own type for it.

export interface TitleProps extends Omit<React.HTMLProps<HTMLHeadingElement>, 'size'> {
  /** the size of the Title  */
  size: keyof typeof BaseSizes;
  /** content rendered inside the Title */
  children?: React.ReactNode;
  /** Additional classes added to the Title */
  className?: string;
  /** the heading level to use */
  headingLevel?: TitleLevel;
}

HTMLImageElement's types are shot for some reason, so for now use extends React.DetailedHTMLProps<React.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>.

Default Props

Use the static attribute as follows:

export class Wizard extends React.Component<WizardProps, WizardState> {
  static defaultProps = {
    hasBodyPadding: true,
    ...
  };

Function Component

These components are pretty easy to convert.

Default Props

export const WizardBody: React.FunctionComponent<WizardBodyProps> = ({
  children,
  hasBodyPadding = true
}: WizardBodyProps) => {
  <main>
    {children}
  </main>
);

Enum as PropTypes

When a property can have only one of a specified set of string values, we will define a enum with each of the possible values as the keys and values. export enum and type out the strings in the prop type definition

export enum OptionsMenuDirection {
  up = 'up',
  down = 'down'
};

export interface OptionsMenuProps extends React.HTMLProps<HTMLDivElement>{
  //prop type declarations
  direction?: 'up' | 'down';
}

Use ReactNode

We will try to use ReactNode as a type rather than ReactElement or ReactType (which is deprecated anyway) for relevant props unless there is a specific reason why you cannot.

Typechecking + Linting

Both of these are required for the build to pass. Run yarn typecheck in react-core to typecheck your component. Run yarn lint:ts to lint your TS files. These results aren't always the same as what VSCode natively says, we need to find a way to share our tsconfig.typecheck.json and tslint.json with VSCode :)

Integration Test

We can't test that our types work as expected for consumers without integration tests. When you convert a component, add a demo to react-integration and that's all (for now...)