为什么类型推断在示例 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/