如何推断通用属性类型?
Posted
技术标签:
【中文标题】如何推断通用属性类型?【英文标题】:How to Infer Generic Property Types? 【发布时间】:2020-04-27 11:34:07 【问题描述】:我不知道如何根据其所在对象的泛型类型推断泛型属性的类型。在下面的例子中,我怎么能说Something.aProp
需要匹配Something的U.obj.prop
的类型呢?
interface Prop
a: number;
interface FancyProp extends Prop
b: number;
interface Obj<T extends Prop>
prop: T;
interface FancyObj extends Obj<FancyProp>
interface Parent<T extends Obj<any>> // <-- the <any> here seems wrong too
obj: T;
interface FancyParent extends Parent<FancyObj>
fancy: number;
class Something<U extends Parent<any>>
aProp: typeof U.obj.prop;
即Something<Parent>.aProp
应该是Prop
类型,而Something<FancyParent>.aProp
应该是FancyProp
类型?
【问题讨论】:
你想要lookup types, aka indexed access types,比如U['obj']['prop']
你能解释一下the <any> here seems wrong too
吗?您的具体问题是什么?
好吧,如果你愿意,你可以写Obj<Prop>
,这会更安全一点,但是根据你实际的非示例接口,你可能需要求助于any
,除非你想要Parent
具有多个通用参数,如 Parent<P extends Prop, T extends Obj<P>>
@jcalz 感谢 cmets!通过添加普通(非花哨)接口的类型约束版本,我似乎能够使用查找类型,并且类中只有一个类型参数:class Something<T extends Parent<any>> aProp: T['obj']['prop']; interface PlainObj extends Obj<Prop> interface PlainParent extends Parent<PlainObj> new Something<PlainParent>().aProp.a; new Something<FancyParent>().aProp.b;
【参考方案1】:
对于您的主要问题,在给定对象类型T
和键类型K
的情况下查找属性值类型的方法是使用lookup types, a.k.a., indexed access types,通过括号语法T[K]
。因此,如果您想查找U
类型对象的"obj"
-keyed 属性的"prop"
-keyed 属性的类型,您可以将该类型写为U["obj"]["prop"]
。
请注意,点语法不适用于类型,即使键类型是字符串文字。如果U.obj.prop
是类型系统中U["obj"]["prop"]
的同义词,那就太好了,但是unfortunately that syntax would collide with namespaces,因为可能有一个名为U
的命名空间,一个名为obj
的子命名空间,以及一个名为@ 的导出类型987654338@,然后U.obj.prop
将引用该类型。
对于您关于any
的cmets,当Y<T>
的类型参数T
有一个generic constraint 时,使用X extends Y<any>
并不是真的错误,但它可能有点没有你能得到的类型安全。如果Y<T>
类型以covariant 的方式与T
相关,那么您可以使用通用约束而不是any
。
这意味着,例如,Parent<T extends Obj<any>>
可以替换为 Parent<T extends Obj<Prop>>
,U extends Parent<any>
可以替换为 U extends Parent<Obj<Prop>>
。
这些更改为您提供如下代码:
interface Parent<T extends Obj<Prop>>
obj: T;
class Something<U extends Parent<Obj<Prop>>>
aProp: U['obj']['prop'];
constructor(u: U)
this.aProp = u.obj.prop;
我还向Something
添加了一个构造函数,因为class properties should be initialized 并且我想表明当u
是U
时,可以为aProp
分配来自u.obj.pop
的值。
这应该可以按您的预期工作:
interface PlainObj extends Obj<Prop>
interface PlainParent extends Parent<PlainObj>
new Something<PlainParent>( obj: prop: a: 1 ).aProp.a; // number
interface FancyObj extends Obj<FancyProp>
interface FancyParent extends Parent<FancyObj>
fancy: number;
new Something<FancyParent>( obj: prop: a: 1, b: 2 , fancy: 3 ).aProp.b; // number
好的,希望对您有所帮助;祝你好运!
Playground link to code
【讨论】:
以上是关于如何推断通用属性类型?的主要内容,如果未能解决你的问题,请参考以下文章