hand sketched logo of electrons orbiting a nucleus

TIL: React.ElementType includes intrinsic and custom types

// from DefinitelyTyped

type ElementType<P = any> =
  | {
      [K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K]
        ? K
        : never;
    }[keyof JSX.IntrinsicElements]
  | ComponentType<P>;

Let's break this down. We'll call the first part of that union IntrinsicElements:

type IntrinsicElements<P> = {
  [K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K]
    ? K
    : never;
}[keyof JSX.IntrinsicElements];

This is an example of the IIMT pattern and captures all the intrinsic elements in JSX.

What do we mean by the word "intrinsic"? Thats any regular ole' HTML element like div, span, h1, etc.

Let's substitute our IntrinsicElements into the original type:

type ElementType<P = any> = IntrinsicElements<P> | ComponentType<P>;

The second part of the union is ComponentType<P>, which is defined as:

type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;

In english you might say "ComponentType is either a custom class component or a custom functional component".

So to wrap all this up, when we see:

type ElementType<P = any> =
  | {
      [K in keyof JSX.IntrinsicElements]: P extends JSX.IntrinsicElements[K]
        ? K
        : never;
    }[keyof JSX.IntrinsicElements]
  | ComponentType<P>;

We can say, "ElementType is the union of all intrinsic (HTML) elements and all custom components (whether class or functional)."


An interesting wrinkle to note, ElementType is defined both in:

The authors explain why this is in the comments here, which discusses no longer needing to support .propTypes


Review all of React's types here in DefinitelyTyped