问题描述
限时送ChatGPT账号..如果一个函数有一个泛型参数
并接受一个与 T
相关的项目数组,那么 T
似乎总是推断为所有元素的交集,即使 T
也可以从函数的返回类型推断出来.示例:
If a function has a generic parameter <T>
and takes an array of items related to T
, it seems T
is always inferred as the intersection of all elements, even if T
could also be inferred from the return type of the function.
Example:
type Item = {foo: string, bar: number};
// A List<Item> may contain items containing partial Items such as {foo: 'FOO'}, {bar: 42}
interface List<T> {
items: Array<Partial<T>>;
}
function list<T>(items: Array<Partial<T>>): List<T> {
return {items};
}
class Baz<T> {
bar(list: List<T>) {
}
}
现在,如果我创建一个 Bar
,它的 bar
方法需要一个 List
.但是,如果我使用便利函数 list()
,即使它返回 List
,T
也不会被推断为 Item
,每个item都是Partial
;相反,T 被推断为所有数组元素的交集,这意味着它基本上会失败,除非所有元素都包含相同的属性.
Now, If I create a Bar<Item>
, its bar
method wants a List<Item>
. However, if I use the convenience function list()
, even though it returns List<T>
, T
is not inferred as Item
, with each item being Partial<Item>
; instead T is inferred as the intersection of all array elements, meaning it basically fails unless all elements contain the same properties.
这意味着以下内容无法编译:
This means that the following does not compile:
new Baz<Item>().bar(list([{foo: 'FOO', bar: 42}, {bar: 42}]))
-> TS2322: 'foo' does not exist in Partial<{bar: number}>
这里,T
被推断为 Partial<{bar: number}
,这是两个元素的交集.
Here, T
was inferred as Partial<{bar: number}
which is the intersection of both elements.
以下有效,因为将 undefined
添加到第二个元素会扩大推断的 T
成为 {foo: string;酒吧:数字} |{foo:未定义;条:数字}
:
The following works since adding undefined
to the second element widens the inferred T
to become {foo: string; bar: number} | {foo: undefined; bar: number}
:
new Baz<Item>().bar(list([{foo: 'FOO', bar: 42}, {bar: 42, foo: undefined}]))
以下当然也有效,因为 T
根本不需要推断:
The following of course also works, since T
does not have to be inferred at all:
new Baz<Item>().bar(list<Item>([{foo: 'FOO', bar: 42}, {bar: 42}]))
问题:有没有办法定义一个具有泛型参数 T
并获取与 T
相关的数组元素的函数,以便 T
是从返回类型而不是数组元素的交集推断,换句话说,允许不相交的数组元素?
Question: Is there a way to define a function having a generic parameter T
and taking array elements related to T
so that T
is inferred from the return type instead of the intersection of the array elements, in other words allowing non-intersecting array elements?
推荐答案
我相信我们与 过多的属性检查 .
下一个数组 [{ foo: 'FOO', bar: 42 }, { bar: 42 }]
被推断为:
Next array [{ foo: 'FOO', bar: 42 }, { bar: 42 }]
is infered to :
({
foo: string;
bar: number;
} | {
bar: number;
foo?: undefined;
})[]
但在我们的例子中,我们有泛型的函数.因此,T
被推断为 {bar: number}
的原因与 :
But in our case we have function with generic. Hence, T
is infered to {bar: number}
for the same reason as :
type A = { foo: string, bar: number };
type B = { bar: number };
type C = A | B;
type Keys = keyof C // 'bar'
因为 bar
是两个联合之间的共享属性.
Because bar
is a shared property between both unions.
我们可以通过这种方式跳过多余的属性检查:
We can skip excess property checking in this way:
type Item = { foo: string, bar: number };
// A List<Item> may contain items containing partial Items such as {foo: 'FOO'}, {bar: 42}
interface List<T> {
items: Array<Partial<T>>;
}
function list<T>(items: Array<Partial<T>>): List<T> {
return { items };
}
class Baz<T> {
bar(list: List<T>) {
}
}
const arr = [{ foo: 'FOO', bar: 42 }, { bar: 42 }];
const result = new Baz<Item>().bar(list(arr))
只需将数组分配给变量即可.
Just assign array to the variable.
更好的选择
只需添加额外的通用:
type Item = { foo: string, bar: number };
// A List<Item> may contain items containing partial Items such as {foo: 'FOO'}, {bar: 42}
type List<T> = {
items: Array<Partial<T>>;
}
// extra generic here
function list<T, A extends Array<Partial<T>>>(items: A): List<T> {
return { items }
}
class Baz<T> {
bar<U extends T>(list: List<U>) {
}
}
const result = new Baz<Item>().bar(list([{ foo: '1', bar: 2 }, { bar: 2 }])) // ok
这篇关于避免推断为数组元素的最小公分母的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
更多推荐
[db:关键词]
发布评论