TypeScript:如何根据另一个泛型推断一个泛型的类型?
TypeScript: How to infer the type of one generic based on another generic?
我有这个代码:
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 将 class B
的方法 b
的参数标记为未知?
我想我明白问题出在哪里了。 class B
有两个泛型类型参数 T
和 O
。 B
的构造函数只接受 A<O>
类型的参数,不接受 T
类型的参数。因此,当您创建一个新的 B
时,无法判断 T
应该绑定到什么。尝试 new B<Type1, Type2>(a)
来帮助编译器。
你认为它应该派生那个T = number
吗?如果条件是 O equals { b: T }
(你不能写),那么那就是真的。但是由于 number extends {}
我们也可以有 T = {}
.
在此代码中,g
的类型为 true
:
type G<T> = { b: number } extends { b: T } ? true : false;
let g: G<{}>;
我们有类型 T
和 O
,其中 O extends {b: T}
。 T
和O['b']
的关系是O['b'] extends T
。这意味着 T
可以是 O['b']
但它也可以是 比 [=17] 更广泛 的任何类型=].
这个推理方向是打字稿无法推断的,因为 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
是某种类型,它是 O
的 b
值或其子集。现在打字稿会将 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'.
我有这个代码:
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 将 class B
的方法 b
的参数标记为未知?
我想我明白问题出在哪里了。 class B
有两个泛型类型参数 T
和 O
。 B
的构造函数只接受 A<O>
类型的参数,不接受 T
类型的参数。因此,当您创建一个新的 B
时,无法判断 T
应该绑定到什么。尝试 new B<Type1, Type2>(a)
来帮助编译器。
你认为它应该派生那个T = number
吗?如果条件是 O equals { b: T }
(你不能写),那么那就是真的。但是由于 number extends {}
我们也可以有 T = {}
.
在此代码中,g
的类型为 true
:
type G<T> = { b: number } extends { b: T } ? true : false;
let g: G<{}>;
我们有类型 T
和 O
,其中 O extends {b: T}
。 T
和O['b']
的关系是O['b'] extends T
。这意味着 T
可以是 O['b']
但它也可以是 比 [=17] 更广泛 的任何类型=].
这个推理方向是打字稿无法推断的,因为 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
是某种类型,它是 O
的 b
值或其子集。现在打字稿会将 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'.