TypeScript:如何根据另一种泛型推断一种泛型的类型?

时间:2021-03-11 16:42:52

标签: typescript type-inference typescript-generics

我有这个代码:

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 的参数标记为未知?

3 个答案:

答案 0 :(得分: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<{}>;

答案 1 :(得分:2)

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

这种推断方向对于 typescript 来说是不可能的,因为 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 是某种类型,它是 bO 值或其子集。现在打字稿会将 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 :(得分:0)

我想我明白问题出在哪里了。类 B 有两个泛型类型参数 TOB 的构造函数只接受 A<O> 类型的参数,但不接受 T 类型的参数。因此,当您创建新的 B 时,无法确定 T 应该绑定到什么。尝试 new B<Type1, Type2>(a) 来帮助编译器。