【问题标题】:Why does TypeScript infer this type for the array item with a union of array types?为什么 TypeScript 会为具有数组类型联合的数组项推断此类型?
【发布时间】:2021-06-16 03:42:40
【问题描述】:

当类型是联合类型并且类型“重叠”时,我无法理解为什么 TypeScript 会为数组元素推断某种类型。我已将其减少到最低限度:

interface Base {
    id: string;
}

interface Child {
    id: string;
    parentId: string;
}

interface Obj {
    nodes1: Base[] | Child[];
    nodes2: (Base | Child)[];
}

const obj: Obj = {
    nodes1: [],
    nodes2: []
};

const node1 = obj.nodes1[0]; // typed as Base
const node2 = obj.nodes2[0]; // typed as Base | Child

如果我更改Base,那么它不仅仅是Child 属性的子集,如下所示:

interface Base {
    baseId: string;
}

现在,node1node2 都被推断为 Base | Child。这是我第一次预料到的。在我的真实代码中,数组可以是Base 类型,也可以是Child 类型,所以打字感觉更好Base[] | Child[],但我现在不得不使用(Base | Child)[]。我可以做一个更大的重构来引入泛型,但这不是一个简单的改变。

为什么类型推断为仅Base 而不是Base | Child

【问题讨论】:

    标签: typescript


    【解决方案1】:

    请参阅microsoft/TypeScript#43667 以获得规范的答案。这是 TypeScript 的设计限制。

    您可能知道:在 TypeScript 的 structural 类型系统中,ChildBase 的子类型,尽管它没有明确声明为这样。所以Child 类型的每个值也是Base 类型的值(反之亦然)。这意味着Child | Base 等同于Base... 尽管编译器并不总是积极地将前者减少 为后者。 (将此行为与 "foo" | string 之类的行为进行比较,编译器总是立即将其简化为 string。)

    通常需要减少子类型,但在某些地方Child | Base 的行为与Base 的行为明显不同,例如excess property checks、IntelliSense 提示或发生在@ 的那种不健全的类型保护987654324@。您还没有说明为什么获得Base 而不是Child | Base 对您很重要,但大概是这些可观察到的差异之一或类似的东西。


    我在这里的建议是首先仔细考虑您是否真的需要这种区别。如果是这样,那么您可能会考虑防止 Base 成为 Child 的子类型,可能通过向其添加可选属性:

    interface Base {
        id: string;
        __baseMarker?: never; // <-- added property
    }
    

    所以现在我们说Base 具有stringid 并且没有__baseMarker 属性,或者具有never 类型的值(这是不可能的)。所以它基本上是“没有__baseMarker 属性”(嗯,它可能是undefined)。这和你原来的定义没有太大区别,但是现在Child extends Base 是假的,Child | Base 不等于Base

    const node1 = obj.nodes1[0]; // typed as Base | Child
    

    Playground link to code

    【讨论】:

    • 谢谢你,很好的回答。我在 GH(和 SO)上进行了搜索,但没有找到答案。代码稍后分支并在Child 上使用一些东西(如果它是Child)。因为 TS 认为它永远不会是 Child,所以它在检查后将类型推断为 never,因此导致错误。
    猜你喜欢
    • 2023-03-15
    • 1970-01-01
    • 2022-01-05
    • 2018-07-26
    • 1970-01-01
    • 2020-09-13
    • 2015-02-24
    • 1970-01-01
    • 2018-03-02
    相关资源
    最近更新 更多