打字稿基于变量动态分配泛型类型

时间:2021-04-19 07:57:40

标签: reactjs typescript types

我想使用类型(或接口)来扩展 React 组件。

定义:

type CoreProps<T> = {
  htmlElement?: 'article' | 'aside' // ...
} & React.HTMLAttributes<T>

所需用途:

type MyComponentProps = {
  myComponentFirstProp: string
  // ...
}

const MyComponent = ({ 
  htmlElement, 
  myComponentFirstProp,
  ...props
}: MyComponentProps & CoreProps): JSX.Element => {
  // ...
}

我知道我可以用 <T> 替换 HTMLElement 但有没有办法根据 CoreProps 中传递的输入 htmlElement 输入 MyComponent

1 个答案:

答案 0 :(得分:0)

JSX.IntrinsicElements类型可以获取相关的HTMLAttributes,所以可以通过这种方式获取。

interface CoreProps<T> {
  htmlElement: T;
}

interface MyComponentProps {
  myComponentFirstProp?: string;
}

const MyComponent = <T extends keyof JSX.IntrinsicElements>(
  props: CoreProps<T> & JSX.IntrinsicElements[T] & MyComponentProps
): JSX.Element => {
  ...
};

<MyComponent htmlElement="img" src="." />; // OK
<MyComponent htmlElement="a" href="." />; // OK
<MyComponent htmlElement="article" />; // OK
<MyComponent htmlElement="a" src="." />; // Error, no 'src' attribute in <a> element

如果你想要相应类型的属性

import { DetailedHTMLFactory, ReactHTML } from 'react';

type EleAttributes<
  T extends keyof ReactHTML
> = ReactHTML[T] extends DetailedHTMLFactory<infer R, infer P> ? R : never;

EleAttributes<'input'>
EleAttributes<'aside'>
...

更新

基于你的例子:

type CoreProps<T extends keyof JSX.IntrinsicElements> = {
  htmlElement?: T;
} & JSX.IntrinsicElements[T];

type ComponentProps = {
  display?: string;
};

const Component = <T extends keyof JSX.IntrinsicElements>({
  htmlElement,
  display,
  style,
  children,
  ...props
}: ComponentProps & CoreProps<T>) => {
  const styles = {
    ...style,

    display,
    // more ...
  };

  // Set default 'div' when htmlElement is undefined
  return React.createElement(
    htmlElement || 'div',
    {
      style: styles,
      ...props,
    },
    children
  );
};