首页 > 解决方案 > 根据道具更改反应组件类型

问题描述

我正在创建一个名为 text 的 React 组件,其中允许更改将要呈现的标签。

export interface TextProps extends HTMLAttributes<HTMLElement> {
  children: ReactNode;
  as?: React.ElementType;
}

问题是我正在尝试使用这样的time元素:

<Text as="time" dateTime="2018-07-07">
  July 7
</Text>

但是 TS 编译器抱怨Property 'dateTime' does not exist on type 'IntrinsicAttributes & TextProps'

我什至尝试使用interface TextProps extends HTMLAttributes<HTMLTimeElement>,但我仍然得到同样的错误。

老实说,我不知道如何在这种组件上获得类型安全

标签: reactjstypescript

解决方案


如果你想as支持任何内置的 HTML 元素,我们可以使用JSX.IntrinsicElements接口,它将 HTML 标记名称映射到它们的 props。

type IntrinsicProps = {
  [K in keyof JSX.IntrinsicElements]: JSX.IntrinsicElements[K] & { as: K; }
}[keyof JSX.IntrinsicElements]

这个映射类型IntrinsicProps提供了所有有效的 props 和as. 我们需要再添加一件事,即如果as未提供可选道具,则可以使用任何道具类型。这取决于您使用的默认标签。

type TextProps = IntrinsicProps | ( HTMLAttributes<HTMLElement> & { as?: never } )

您可以添加children到道具或键入使用自动React.FC添加的组件children

const Text: React.FC<TextProps> = (props) => {
  /* ... */
}

现在您可以添加dateTime为道具,但前提是您的as类型支持它!

这有效:

<Text as="time" dateTime="2018-07-07">July 7</Text>

但这会给出错误“'dateTime'类型上不存在属性IntrinsicAttributes & ClassAttributes<HTMLDivElement> & HTMLAttributes<HTMLDivElement> & { ...; } & { ...; }

<Text as="div" dateTime="2018-07-07">July 7</Text>

打字稿游乐场链接


推荐阅读