如果一个函数有一个泛型参数<T>,并且接受一个与T相关的项数组,那么似乎总是将T推断为所有元素的交集,即使T也可以从函数的返回类型推断出来。示例:
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<Item>,它的bar方法需要一个List<Item>。但是,如果我使用方便函数list(),即使它返回List<T>,T也不会被推断为Item,每个项都是Partial<Item>;相反,T被推断为所有数组元素的交集,这意味着它基本上失败了,除非所有元素都包含相同的属性。
这意味着以下内容没有编译:
new Baz<Item>().bar(list([{foo: 'FOO', bar: 42}, {bar: 42}]))
-> TS2322: 'foo' does not exist in Partial<{bar: number}>这里,T被推断为Partial<{bar: number},它是两个元素的交集。
以下工作是因为将undefined添加到第二个元素中,可以将推断的T扩展为{foo: string; bar: number} | {foo: undefined; bar: number}
new Baz<Item>().bar(list([{foo: 'FOO', bar: 42}, {bar: 42, foo: undefined}]))当然,以下内容也有效,因为根本不需要推断T:
new Baz<Item>().bar(list<Item>([{foo: 'FOO', bar: 42}, {bar: 42}]))问:是否有一种方法可以定义一个具有泛型参数T的函数,并接受与T相关的数组元素,以便从返回类型而不是数组元素的交集中推断T,换句话说,允许不相交的数组元素?
发布于 2021-03-24 10:03:29
我相信我们和超额财产检查有一笔交易。
下一个数组[{ foo: 'FOO', bar: 42 }, { bar: 42 }]推断为:
({
foo: string;
bar: number;
} | {
bar: number;
foo?: undefined;
})[]但在我们的例子中,我们有泛型功能。因此,T被推断为{bar: number}的原因与以下相同:
type A = { foo: string, bar: number };
type B = { bar: number };
type C = A | B;
type Keys = keyof C // 'bar'因为bar是两个联合之间的共享属性。
我们可以以这种方式跳过多余的属性检查:
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))只需将数组赋值给变量。
更好的选项
只需添加额外的泛型:
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 }])) // okhttps://stackoverflow.com/questions/66777727
复制相似问题