【问题标题】:TypeScript: How to infer the type of one generic based on another generic?TypeScript:如何根据另一个泛型推断一个泛型的类型?
【发布时间】:2021-06-09 16:43:06
【问题描述】:

我有这个代码:

class A<T> {
    a(t: T) {
        console.log(t);
    }
}

class B<T, O extends {b: T}> {
    constructor(public a: A<O>) {
    }

    b(t: T) {
        console.log(t)
    }
}

const a = new A<{b: number}>(); // type: A<{ b: number; }>

const b = new B(a); // type: B<unknown, { b: number; }>

为什么 TypeScript 将 B 类的方法 b 的参数标记为未知?

【问题讨论】:

标签: typescript type-inference typescript-generics


【解决方案1】:

我们有TO 类型,其中O extends {b: T}TO['b'] 之间的关系就是O['b'] extends T。这意味着T 可以完全是O['b'],但也可以是比O['b']更广泛的任何类型。

打字稿不可能推断出这种推理方向,因为T 的类型有无数种,例如number extends T。正如@md2perpe 所建议的那样,您可以拥有一个非常广泛的类型,例如any{}。您可以有一个包含 number 的联合,例如 string | number 等。

为了能够推断出第二个参数,我们需要 extends 以另一种方式进行。我们需要知道T 必须比O['b']。我们可以这样写:

class B<T extends O['b'], O extends {b: any}> {

这里我们说O 是一个带有b 属性的对象。我们说T 是某种类型,它要么是Ob 值,要么是它的子集。现在 typescript 会将T 推断为O['b']

const a = new A<{b: number}>(); // type: A< b: number; }>

const b = new B(a); // type: B<number, { b: number; }>

b.b(5) // takes type: number

请注意,您仍然可以手动将T 设置为更窄的类型:

const specificB = new B<5, {b: number}>(a); // type: B<5, { b: number; }>

specificB.b(10); // error: Argument of type '10' is not assignable to parameter of type '5'.

Typescript Playground Link

【讨论】:

  • 非常感谢。很有帮助。
【解决方案2】:

你认为它应该派生出T = number 吗?如果条件是O equals { b: T }(你不能写),那么那将是真的。但是由于number extends {} 我们也可以拥有T = {}

在此代码中,g 的类型为 true

type G<T> = { b: number } extends { b: T } ? true : false;
let g: G<{}>;

【讨论】:

    【解决方案3】:

    我想我明白问题出在哪里了。类B 有两个泛型类型参数TOB 的构造函数只接受 A&lt;O&gt; 类型的参数,但不接受 T 类型的参数。所以当你创建一个新的B 时,没有办法知道T 应该绑定到什么。尝试new B&lt;Type1, Type2&gt;(a) 帮助编译器。

    【讨论】:

    • 根据我的经验,第一个泛型类型应该从第二个泛型类型推断出来。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-05
    • 2019-09-17
    • 1970-01-01
    • 1970-01-01
    • 2021-06-01
    • 2017-10-04
    • 2020-07-23
    相关资源
    最近更新 更多