我想像这样声明类型:
type ElementCreatorParameters = {
tagName: keyof HTMLElementTagNameMap
children?: Array<ElementCreatorParameters>
onCreate?(element: HTMLElementTagNameMap[tagName]): void
}
第一个问题是,我不能使用字段tagName
的值来定义element
的类型(如果我是正确的,那是因为类型必须是静态的)
第二个问题是,当我开始使用泛型类型时,我需要将此泛型类型传递到children
字段中:
type ElementCreatorParameters<T extends keyof HTMLElementTagNameMap> = {
tagName: T
children?: Array<ElementCreatorParameters<T>>
onCreate?(element: HTMLElementTagNameMap[T]): void
}
但children
与其父代的泛型类型不同
我希望所有这些都能像这样定义对象:
{
tagName: 'form',
onCreate: (element) => {
// Here the element must be HTMLFormElement
element
},
children: [
{
tagName: 'input',
onCreate: (element) => {
// Here the element must be HTMLInputElement
element
},
children: [
{
tagName: 'a',
onCreate: (element) => {
// Here the element must be HTMLAnchorElement
element
},
},
]
},
],
}
1条答案
按热度按时间wmvff8tz1#
您可以将
ElementCreatorParameters
表示为联合类型,其中联合中的每个成员对应于keyof HTMLElementTagNameMap
中的tagName
的一个选择。当然,那个联盟里会有100多个成员,所以手工写出来会很烦人……但这是一个有限的数字,所以联合至少是一个可能的解决方案。幸运的是,我们不需要把工会成员一个个写出来;我们可以让编译器为我们计算它。就像这样:一般的方法是先生成一个mapped type,然后再生成index into it及其所有键,以获得Map类型的属性的并集。这可以称为microsoft/TypeScript#47109中创造的 * 分布式对象类型 *。如果你有一组键
type KK = K1 | K2 | K3 | ⋯
,那么{[K in KK]: F<K>}[KK]
将计算为F<K1> | F<K2> | F<K3> | ⋯
。在上面的例子中,
KK
是keyof HTMLElementTagNameMap
,F<K>
是所以
ElementCreatorParameters
是一个大的联合,如果你在支持IntelliSense的IDE中悬停quickinfo,你可以看到它:让我们测试一下:
看起来不错!所有的
onCreate
参数都是根据ElementCreatorParameters
联合体的相应成员上下文推断出来的。Playground链接到代码