typescript - 为什么 typescript 不能通过深层/嵌套属性推断 Switch 语句中的类型

标签 typescript

为什么类型推断在示例 A 中有效,而在 B 中无效?唯一的区别是类型字符串的位置。 block.type对比 block.meta.type . A 编译并推断类型和 B 结果。

// Example B errors
Property 'a' does not exist on type 'Block'. Property 'a' does not exist on type 'ITwo'.
Property 'b' does not exist on type 'Block'. Property 'b' does not exist on type 'IOne'.
如何在不改变 IOne 的数据结构的情况下让 B 正确编译和推断或 ITwo ?

示例 A
https://www.typescriptlang.org/play?#code/KYOwrgtgBAKgmgBQKJQN5QPIDkUF4oDkA9iMAQDSwDqGU+BALgO5EEC+AUBwJYgPAAnAGYBDAMbAoASQyk0HKIqgiAXFADODAbwDm5BUoYBPAA7A18ZADpsSDpx59BoidJgt5SqACM1m7SB6BorGZhaISFYwNPZcoZIAQgA2RGIA1nTSspIAPm4sXADaALpWECImABSV3inpKsmpaQCUdAB8nkrqTNwMYgAWUDV1aVbxrajBXlBiIuqSlpG2KlPTSrVNViKraz4CwCJpANw7irPzsBFRNCu70xvpVt5Qp-f7hydenGzNR0A
enum TYPE { ONE = 'one', TWO = 'two'}

interface IOne {
    a: string,
    type: TYPE.ONE
}

interface ITwo {
    b: string,
    type: TYPE.TWO
}

type Block = IOne | ITwo

[].map((block:Block) => {
    switch (block.type) {
        case TYPE.ONE:
            block.a
            break;
        case TYPE.TWO:
            block.b 
            break;
    }
});

示例 B
https://www.typescriptlang.org/play?#code/KYOwrgtgBAKgmgBQKJQN5QPIDkUF4oDkA9iMAQDSwDqGU+BALgO5EEC+AUBwJYgPAAnAGYBDAMbAoASQyk0HKIqgiAXFADODAbwDm5BUojAGIqGtQGlShgE8ADsDXxkAOmxJLUTpx59BoiWkYFnkrACM1TW0QPU8jEzNQq2t7R1hEJBcYGk9vLlsHKAAhABsiMQBrOmlZSQAfIJYuAG0AXRcIETsACm6wssqVUvKKgEo6AD4kxXUmbgYxAAsoPoGKjuMRFwLgcYtkpTERdUlnTPcVTwPFfpGXESvrsIFgEQqAbkfFI5P012yMJdrslbpUXGEoF8QS83p8rN5Ru8gA
enum TYPE { ONE = 'one', TWO = 'two'}

interface IOne {
    a: string,
    meta : {
        type: TYPE.ONE
    }
}

interface ITwo {
    b: string,
    meta : {
        type: TYPE.TWO
    }
}

type Block = IOne | ITwo

[].map((block:Block) => {
    switch (block.meta.type) {
        case TYPE.ONE:
            block.a
            break;
        case TYPE.TWO:
            block.b 
            break;
    }
});
提前致谢,J。

最佳答案

这是在 Nested Tagged Unions issue 下讨论和跟踪的在 TS repo 中。简短回答您的问题:在问题得到解决之前,您将无法做您想做的事情 .
类型保护和泛型
也就是说,您仍然可以通过类型保护和泛型的组合来实现这一点。类型保护将执行运行时检查嵌套值是否与预期类型匹配,泛型将删除一些样板,否则检查联合中的每个类型是必要的。
由于我们正在讨论的示例非常抽象,因此对于您的现实世界代码,这可能不是一个实用的解决方案。
假设只有少数类型,去掉 switch 语句以支持条件返回( "Return early, return often" )是有意义的。这将使使用类型保护变得微不足道:

enum TYPE { ONE = 'one', TWO = 'two'}

interface IOne {
    a: string,
    meta : {
        type: TYPE.ONE
    }
}

interface ITwo {
    b: string,
    meta : {
        type: TYPE.TWO
    }
}

type Block = IOne | ITwo;

export const isBlock = <T extends Block>(
  b: Block,
  metaType: TYPE,
): b is T =>
  b.meta.type === metaType;

[].map((block: Block) => {
    if (isBlock<IOne>(block, TYPE.ONE)) {
        return block.a;
    }
    
    return block.b; 
});

关于typescript - 为什么 typescript 不能通过深层/嵌套属性推断 Switch 语句中的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65139900/

相关文章:

typescript - nestjs 拦截并修改传出的 http 请求

javascript - 如何在本地 javascript 函数中使用 .d.ts

typescript - 为什么无效合并运算符不能作为 typescript 中的打字员工作?

javascript - 使用 TypeScript/Angular2 循环对象的键/值

angular - 如何使用 Angular 5 在单击按钮时调用多个方法?

node.js - 如何连接 Angular2 + Webpack + Node + Express?

javascript - 如何将复杂数组声明为另一个属性 Typescript 的属性

node.js - 最新的 Angular cli 无法在 Windows 上创建新应用程序

json - Angular environment.ts 问题 JSON。然而 environment.prod.ts

javascript - 如何使用json_to_sheet提取xlxs中的json数据