首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >避免推断为数组元素的最小公分母

问避免推断为数组元素的最小公分母
EN

Stack Overflow用户
提问于 2021-03-24 08:59:59
回答 1查看 32关注 0票数 1

如果一个函数有一个泛型参数<T>,并且接受一个与T相关的项数组,那么似乎总是将T推断为所有元素的交集,即使T也可以从函数的返回类型推断出来。示例:

代码语言:javascript
复制
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被推断为所有数组元素的交集,这意味着它基本上失败了,除非所有元素都包含相同的属性。

这意味着以下内容没有编译:

代码语言:javascript
复制
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}

代码语言:javascript
复制
new Baz<Item>().bar(list([{foo: 'FOO', bar: 42}, {bar: 42, foo: undefined}]))

当然,以下内容也有效,因为根本不需要推断T:

代码语言:javascript
复制
new Baz<Item>().bar(list<Item>([{foo: 'FOO', bar: 42}, {bar: 42}]))

问:是否有一种方法可以定义一个具有泛型参数T的函数,并接受与T相关的数组元素,以便从返回类型而不是数组元素的交集中推断T,换句话说,允许不相交的数组元素?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-03-24 10:03:29

我相信我们和超额财产检查有一笔交易。

下一个数组[{ foo: 'FOO', bar: 42 }, { bar: 42 }]推断为:

代码语言:javascript
复制
({
    foo: string;
    bar: number;
} | {
    bar: number;
    foo?: undefined;
})[]

但在我们的例子中,我们有泛型功能。因此,T被推断为{bar: number}的原因与以下相同:

代码语言:javascript
复制
type A = { foo: string, bar: number };
type B = { bar: number };
type C = A | B;

type Keys = keyof C // 'bar'

因为bar是两个联合之间的共享属性。

我们可以以这种方式跳过多余的属性检查:

代码语言:javascript
复制
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))

只需将数组赋值给变量。

更好的选项

只需添加额外的泛型:

代码语言:javascript
复制
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
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66777727

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档