首页 > 解决方案 > 如何推断通用属性类型?

问题描述

我不知道如何根据它所在对象的泛型类型推断泛型属性的类型。在下面的例子中,我怎么能说Something.aProp需要匹配 Something's 的类型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

标签: typescripttypescript-generics

解决方案


对于您的主要问题,在给定对象类型T和键类型的情况下查找属性值类型的方法是通过括号语法K使用查找类型,即索引访问类型T[K]。因此,如果您想查找 type 对象的"prop"-keyed 属性的"obj"-keyed 属性的类型U,您可以将该类型写为U["obj"]["prop"]

请注意,点语法不适用于类型,即使键类型是字符串文字。如果U.obj.prop是类型系统中的同义词就好了U["obj"]["prop"],但不幸的是,该语法会与 namespaces 冲突,因为可能有一个名为 的命名空间U,一个名为 的子命名空间,一个名为obj的导出类型prop,然后U.obj.prop会引用该类型。


对于您对 的评论,使用when的类型参数具有泛型约束any并没有,但它的类型安全性可能比您所能获得的要少一些。如果类型以协变方式相关,那么您可以使用泛型约束而不是. X extends Y<any>Y<T>TY<T>Tany

这意味着,例如,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因为应该初始化类属性,并且我想表明aProp可以从u.obj.pop什么时候开始u为它分配一个值U

这应该可以按您的预期工作:

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 代码链接


推荐阅读