我问了一个关于这个基础概念更加复杂版本的问题。
关联链接:可以在 TypeScript 中使用通用 JSX.Element 吗
我将其缩小到核心元素:
这是从 TypeA
获取参数的 Object A
type TypeA = {
label: string
value: number
}
const ObjA = ({ label, value }:TypeA) => {
return <div>
<div>Label: {label}</div>
<div>Value: {value}</div>
</div>
}
这是从TypeB
获取参数的Object B
type TypeB = {
label: string
value: string
bool: boolean
}
const ObjB = ({ label, value, bool }:TypeB) => {
return <div>
<div>Label: {label}</div>
{bool && <div>Value: {value}</div>}
</div>
}
现在我将这个 ComponentGroup 存储在一个数组中,并创建一个由该数组组成的 Type :
const ComponentCollection = [
ObjA,
ObjB
] as const
type Components = typeof ComponentCollection[number]
然后我创建一个通用组件:
interface GenericProps<T extends Components> {
Component: T
title: string
}
const Generic = <T extends Components,>({ Component, title, ...props }:GenericProps<T>) => {
return (
<div>
<label>{title}</label>
<Component {...props}/>
</div>
)
}
最后,我可以按以下方式调用通用组件:
<Generic Component={ObjA} title={'Usage A'} label={'Object A'} value={'String A'}/>
<Generic Component={ObjB} title={'Usage B no Bool'} label={'Object B'} value={0}/>
<Generic Component={ObjB} title={'Usage B with Bool'} label={'Object B'} value={0} bool/>
尽管它在JavaScript中运行得非常好,但我在输入方面出了些问题。
我设置了一个TS-Playground和一个Codepen:
TS-Playground:https://tsplay.dev/WvVarW
Codepen:https://codepen.io/Cascade8/pen/eYezGVV 目标:
- 将上述代码转换为正确的TypeScript代码
- 编译时没有任何TS错误或
/@ts-ignore
- 使智能提示工作,因此如果您键入
<Generic Component={ObjA} ...
,它会显示此对象可用的类型属性。在这种情况下:label={string: } value={string: }
- 如果可能的话,我们的EsLint要求我们使用箭头函数,而不是类或旧的函数语法。
- 将对象作为子元素传递。
我知道这样可以工作,但这并不是首选解决方案,因为主项目有很多像这样的组,会像这样呈现。
为什么在JavaScript中非常简单的东西在TypeScript中不能工作呢。
Generic
内部,props的类型没有指定为与Components
中的条目匹配,而是在GenericProps
内部完成的。不过,在使用它们的那一行中,你可以断言类型。你可以在里面直接转换为as any
。这不会影响Generic
内部的类型。 - TomComponent(props)
,而不是<Component {...props}/>
。我相信这将避免导致问题的LibraryManagedAttributes。 - sam256