这可能是一个重复的问题。但是我似乎找不到答案,因此,如果已经回答,请随时将我指向某个地方。
使用泛型时,我发现 typescript 会根据我是否包装用作数组成员的泛型来推断出不同的类型。例如,

// Set up
type Wrapped<I> = { _i: I };

// Not working example
function foo1<TInner extends unknown>(bar: Wrapped<TInner>[]) {
  return bar;
}
const a = foo1([{ _i: 5 }, { _i: "six" }]); // TInner = number, compiler complains about second array member despite the fact that it's inferring it

// Working example
function foo2<TInner extends Wrapped<unknown>>(bar: TInner[]) {
  return bar;
}
const b = foo2([{ _i: 5 }, { _i: "six" }]); // TInner = Wrapped<number> | Wrapped<string>
为什么会这样呢?我缺少的文档中有东西吗?更笼统地说,有人能给我一个很好的解释,说明 typescript 如何推论泛型吗?

最佳答案

仔细研究一下代码的编写方式。

// Slightly edited given example

type Wrapped<I> = { _i: I };

function foo<T extends unknown>(baz: Wrapped<T>[]) {}

foo1([ { _i: 5 }, { _i: "six" } ]);

function bar<T extends Wrapped<unknown>>(baz: T[]) {}

foo2([ { _i: 5 }, { _i: "six" } ]);
定义foo的通用参数T extends unknown的方式意味着T可以是任何东西,由unknown表示,但它是 1
实际函数的参数为​​Wrapped<T>[];分解它,foo接受一个Wrapped<T>数组,这意味着它接受一个Wrapped对象的列表,但是每个对象必须具有相同的类型,因此它可以接受[ { _i: 1 }, { _i: 2 }, { _i: 3 } ][ { _i: 'a' }, { _i: 'b' }, { _i: 'c' } ],但是不能创建并集/元组因为它是输出,所以类似[ { _i: 'a' }, { _i: 2 }, { _i: Symbol(NaN) } ]的操作将失败,因为此类型实际上是Wrapped<string | number | symbol>[],而前两个分别是Wrapped<number>[]Wrapped<string>[]
另一方面,bar定义为<T extends Wrapped<unknown>>。在这种情况下,T只是Wrapped类型的对象,无需关心其type参数是什么,只要它具有Wrapped对象的一般形状即可。
在这里,无论它们是否都是相同类型,它都可以采用Wrapped对象的数组。
总结起来,foo接受相同类型的连续数组,而bar接受任何Wrapped对象的数组。

关于javascript - 如果包装数组成员, typescript 泛型为什么会推断出不同的类型?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/64703988/

10-09 17:47