如何推断泛型 属性 类型?

How to Infer Generic Property Types?

我不知道如何根据其所在对象的通用类型推断通用 属性 的类型。在下面的例子中,我怎么能说 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?

类型

对于您的主要问题,在给定对象类型 T 和键类型 K 的情况下查找 属性 值类型的方法是使用 lookup types, a.k.a., indexed access types, 通过括号语法 T[K]。因此,如果你想查找 U 类型对象的 "prop" 键控 属性 的 "obj" 键控 属性 的类型,你会将该类型写为 U["obj"]["prop"].

请注意,点语法不适用于类型,即使键类型是字符串文字也是如此。如果 U.obj.prop 在类型系统中是 U["obj"]["prop"] 的同义词就好了,但是 unfortunately that syntax would collide with namespaces,因为可以有一个名为 U 的命名空间,以及一个名为 obj,带有名为 prop 的导出类型,然后 U.obj.prop 将引用该类型。


关于您对 any 的评论,在 Y<T> 的类型参数 [=12= 时使用 X extends Y<any> 并不是真的 错误 ] 有一个 generic constraint, but it might be a bit less type safe than you can get. If the type Y<T> is related to T in a covariant 的方式,那么你可以使用通用约束而不是 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 并且我想证明 aProp 可以从 u.obj.pop 中赋值 uU.

这应该会像您预期的那样工作:

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