我浏览了几个现有的解决方案和帖子,但找不到任何解决方案。
所以,我将 React 与 Typescript 和 styled-component 结合使用。
我的项目的一部分是 Heading
组件。理想情况下,我想像 <Heading level={2}>Hello world!</Heading>
一样在我需要的地方使用它。
Here is the simplified Codesandbox Code of it
然而,<S.Heading
在我的 Linter 中抛出错误,即使它看起来在视觉上工作。
错误
<块引用>这个 JSX 标签的 'children' 属性需要类型 'never',这需要多个孩子,但只提供了一个孩子。ts(2745)
没有与此调用匹配的过载。 这个 JSX 标签的 'children' 属性需要类型 'never',这需要多个孩子,但只提供了一个孩子。ts(2769)
不确定我的代码有什么问题,因为我认为我遵循了大多数建议..
答案 0 :(得分:1)
Typescript template literal types 并不像你想象的那么聪明。您可能希望 h${props.level}
根据 "h1" | "h2" | ...
变量的类型计算为联合类型 props.level
。相反,它只是 string
。因此,您需要在代码中的某处使用 as
断言来声明此 string
是 JSX.IntrinsicElements
的有效键。
获取联合 "h1" | "h2" | ...
作为类型很困难,因为 Props['level']
是 number
文字的联合,而不是 string
文字。但我们并不真的需要联合,因为 t 并不重要,它是哪种标题类型。您可以使用 as "h1"
,您会没事的。
export default function Heading(props: Props) {
return <S.Heading as={`h${props.level}` as "h1"}>{props.children}</S.Heading>;
}
出于好奇,我想看看是否可以从 h*
中提取有效的 JSX.IntrinsicElements
标签。我想出了一个几乎基于字符串长度的解决方案,但我忘记了hr
!
type HTag = {
[K in keyof JSX.IntrinsicElements]: K extends `h${string}${infer B}` ? B extends "" ? K : never : never
}[keyof JSX.IntrinsicElements]
评估为:
"h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "hr"