[React Typescript] ElementType, ComponentType

发布时间 2023-08-23 14:16:02作者: Zhentiw

The ElementTypetype helper is a bit unusal because it accepts some props and derives what types of components would be able to recieve those props.

Here we have an Example component that accepts audio and video as well as ComponentType<P>.

When we pass it an autoPlay prop:

export type Example = React.ElementType<{
  autoPlay?: boolean;
}>;

// hovering over Example shows:
type Example =
  | "audio"
  | "video"
  | React.ComponentType<{
      autoPlay?: boolean | undefined;
    }>;

ElementType can tell that this prop can be used with an audio or video element, or a React Component Type that accepts autoPlay as a prop.

Any custom component that you think of will correspond to ElementType, as well as any other element defined in JSX.IntrinsicElements that can receive props.

For example, many elements can accept an href prop. If you defined an ElementType to accept an optional href, all of a sudden there are several possible elements that can be used:

type Example = React.ElementType<{
  href?: string;
}>;

// hovering over Example shows:

type Example = "symbol" | "a" | "area" | "base" | "link" |
"svg" | "animate" | "animateMotion" | "animateTransform" |
"circle" | "clipPath" | "defs" | "desc" | "ellipse" |
"feBlend" | "feColorMatrix" | ... 46 more ...
| React.ComponentType<...>

 

 

ComponentType

Here we have a FuncComponent and a ClassComponent that take a prop1 that is a string:

const FuncComponent = (props: { prop1: string }) => {
  return null;
};

class ClassComponent extends React.Component<{
  prop1: string;
}> {
  render(): React.ReactNode {
    this.props.prop1;
    return null;
  }
}

By using the ComponentType type helper, you can ensure that only components that accept prop1 are passed to this array as seen in tests2:

const tests2: Array<React.ComponentType<{ prop1: string }>> = [
  FuncComponent,
  ClassComponent,
];

If we change the prop name in ClassComponent to propTwo, we will see an error because propOne is not assignable to propTwo:

class ClassComponent extends React.Component<{
  prop2: string;
}> {
  render(): React.ReactNode {
    this.props.prop2;
    return null;
  }
}

const tests2: Array<React.ComponentType<{ prop1: string }>> = [
  FuncComponent,
  ClassComponent, // Error!
];

// Error message on ClassComponent:
// Type 'ComponentType<{ prop2: string; }>' is not assignable to type 'ComponentType<{ prop1: string; }>'.

This demonstrates that ComponentType works can represent either functional or class components.

ComponentType is useful when working with higher-order components when you want to ensure that a specific prop type is being passed to a component.