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

Jus*_*lex 3 type-inference typescript 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; }>
Run Code Online (Sandbox Code Playgroud)

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

Lin*_*ste 5

我们有类型TO地点O extends {b: T}T和之间的关系O['b']是这样的O['b'] extends T。这意味着它T可以是精确的,但也可以是比 更广泛的O['b']任何类型。O['b']

Typescript 不可能推断出这种推理方向,因为T这样的类型有无限多种number extends T。您可以有一个非常广泛的类型,如@ anymd2perpe 或{}@md2perpe 所建议的。你可以有一个包含numberlikestring | number等的联合体。

为了能够推断出第二个参数,我们需要extends采用相反的方式。我们需要知道T一定比O['b']。我们可以这样写:

class B<T extends O['b'], O extends {b: any}> {
Run Code Online (Sandbox Code Playgroud)

这里我们说这O是一些具有属性的对象b。我们说这T是某种类型,它要么是它的bO,要么是它的子集。现在打字稿将推断TO['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
Run Code Online (Sandbox Code Playgroud)

请注意,您仍然可以手动设置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'.
Run Code Online (Sandbox Code Playgroud)

Typescript Playground 链接