我有这个代码:
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
的参数标记为未知?
答案 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)
我们有 T
和 O
类型,其中 O extends {b: T}
。 T
和 O['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
是某种类型,它是 b
的 O
值或其子集。现在打字稿会将 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'.
答案 2 :(得分:0)
我想我明白问题出在哪里了。类 B
有两个泛型类型参数 T
和 O
。 B
的构造函数只接受 A<O>
类型的参数,但不接受 T
类型的参数。因此,当您创建新的 B
时,无法确定 T
应该绑定到什么。尝试 new B<Type1, Type2>(a)
来帮助编译器。