[英]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.