简体   繁体   English

如果包装数组成员,为什么打字稿泛型会推断不同的类型?

[英]Why does typescript generics infer different types if array member is wrapped?

This may be a duplicate question;这可能是一个重复的问题; however I can't seem to find an answer, so please feel free to point me somewhere if it has already been answereded.但是我似乎找不到答案,所以如果已经有人回答了,请随时指出我的地方。

When working with generics, I find that typescript infers different types depending on whether I wrap a generic used as an array member.在使用泛型时,我发现 typescript 会根据我是否包装用作数组成员的泛型来推断不同的类型。 For example,例如,

// 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>

Why is this the case?为什么会这样? Is there something in the documentation I'm missing?文档中是否有我遗漏的内容? More generically, can anyone point me to a good explanation of how typescript does inference of generics?更笼统地说,有人能指出我对打字稿如何推断泛型的一个很好的解释吗?

Look at the way that the code is written very closely.仔细看看代码的编写方式。

// 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" } ]);

The way foo 's generic parameter is defined, T extends unknown , means that T can be anything, denoted by the unknown , but it's 1 thing.定义foo的泛型参数的方式, T extends unknown ,这意味着T可以是任何东西,由unknown表示,但它是件事。

The actual function's parameter is Wrapped<T>[] ;实际函数的参数是Wrapped<T>[] breaking it down, foo accepts an array of Wrapped<T> , meaning it accepts a list of Wrapped objects, but every one of them must have the same type , so it could accept [ { _i: 1 }, { _i: 2 }, { _i: 3 } ] , or [ { _i: 'a' }, { _i: 'b' }, { _i: 'c' } ] , but it cannot create a union/tuple as it's output, so something like [ { _i: 'a' }, { _i: 2 }, { _i: Symbol(NaN) } ] would fail, because this type is actually Wrapped<string | number | symbol>[]分解一下, foo接受一个Wrapped<T>数组,这意味着它接受一个Wrapped对象列表,但每个对象都必须具有相同的 type ,因此它可以接受[ { _i: 1 }, { _i: 2 }, { _i: 3 } ][ { _i: 'a' }, { _i: 'b' }, { _i: 'c' } ] ,但它不能创建联合/元组,因为它是输出,所以像[ { _i: 'a' }, { _i: 2 }, { _i: Symbol(NaN) } ]会失败,因为这个类型实际上是Wrapped<string | number | symbol>[] Wrapped<string | number | symbol>[] Wrapped<string | number | symbol>[] , whereas the former two were Wrapped<number>[] , and Wrapped<string>[] , respectively. Wrapped<string | number | symbol>[] ,而前两个分别是Wrapped<number>[]Wrapped<string>[]

bar , on the other hand, is defined as <T extends Wrapped<unknown>> .另一方面, bar被定义为<T extends Wrapped<unknown>> In this case, T is just an object of the type Wrapped , without care to what it's type parameter is, as long as it has the general shape of a Wrapped object.在这种情况下, T只是Wrapped类型的对象,无需关心它的类型参数是什么,只要它具有Wrapped对象的一般形状即可。 Here, it can take an array of Wrapped objects, regardless of whether they are all of the same types, or not.在这里,它可以接受一组Wrapped对象,无论它们是否都是相同的类型。

Summing it up, foo is accepting a contiguous array of the same type, whereas bar is accepting an array of any Wrapped objects.总结一下, foo接受相同类型的连续数组,而bar接受任何Wrapped对象的数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM