英文:
TypeScript type narrowing not working for union type
问题
Type narrowing 在这些代码片段中为什么不起作用?
const xyz: { num: number } | { str: string }
if ("num" in xyz) {
xyz // { num: number; } | { str: string; }
}
我甚至尝试添加了一个类型判别字段:
const xyz: { type: "num", num: number } | { type: "str", str: string }
if (xyz.type === "num") {
xyz // { type: "num", num: number } | { type: "str", str: string }
}
我使用的是 TypeScript 版本 5.0.2。
英文:
Why is type narrowing not working in these snippets?
const xyz: { num: number } | { str: string }
if ("num" in xyz) {
xyz // { num: number; } | { str: string; }
}
I even tried adding a type discriminant:
const xyz: { type: "num", num: number } | { type: "str", str: string }
if (xyz.type === "num") {
xyz // { type: "num", num: number } | { type: "str", str: string }
}
I'm using Typescript version 5.0.2
答案1
得分: 1
当TypeScript类型检查器抱怨先前的错误或警告时,似乎会影响正确的类型缩小。
在我的情况下,解决方案是修复(或消除)未初始化变量xyz
(以及其他先前的类型错误),然后类型缩小再次正常工作。
简而言之,看似不相关的类型错误可能会使类型检查器处于不良状态;确保首先修复简单的错误,然后再解决任何奇怪的错误。
英文:
It seems when the Typescript type-checker complains about prior errors or warnings, then that can throw off proper type narrowing.
In my case, the solution was to fix (or silence) the use of the un-initialized variable xyz
(and other prior type errors), and type narrowing worked properly again.
TL;DR Seemingly unrelated type errors can put the type-checker in a bad state; Ensure simple errors are fixed first before tackling any weird errors.
答案2
得分: -1
Type narrowing在你的示例中不起作用,因为{ num: number } | { str: string }
和{ type: "num", num: number } | { type: "str", str: string }
的类型联合不是互斥的,这意味着这种类型的变量可以拥有属于两个联合成员的属性。
在第一个示例中,即使你检查了xyz中的"num",xyz仍然可以是{ str: string }
类型。这是因为xyz可以具有属性str: string,它是第二个联合成员的成员。
类似地,在第二个示例中,检查xyz.type === "num"
只能将类型缩小到{ type: "num", num: number } | { type: "str", str: string }
,而不能缩小到具体的类型。因此,xyz仍然可以具有属性str: string
。
要使类型缩小在这些示例中起作用,你需要使用一个可以将类型缩小到联合成员的特定成员的类型保护。例如,你可以定义一个自定义的类型保护函数,如下所示:
function isNum(obj: { num?: unknown }): obj is { num: number } {
return typeof obj.num === "number";
}
然后,你可以在代码中使用这个类型保护来缩小xyz的类型:
const xyz: { num: number } | { str: string } = { num: 42 };
if (isNum(xyz)) {
xyz // { num: number }
}
类似地,对于第二个示例,你可以定义一个类型保护函数,如下所示:
function isNum(obj: { type?: unknown }): obj is { type: "num", num: number } {
return obj.type === "num";
}
然后,你可以在代码中使用这个类型保护来缩小xyz的类型:
const xyz: { type: "num", num: number } | { type: "str", str: string } = { type: "num", num: 42 };
if (isNum(xyz)) {
xyz // { type: "num", num: number }
}
英文:
Type narrowing is not working in your examples because the type union of { num: number } | { str: string } and { type: "num", num: number } | { type: "str", str: string }
are not mutually exclusive, meaning that a variable of this type can have a property that belongs to both union members.
In the first example, even though you checked that "num" in xyz, xyz can still be of type { str: string }
. This is because xyz can have the property str: string which is a member of the second union member.
Similarly, in the second example, checking xyz.type === "num"
only narrows down the type to { type: "num", num: number } | { type: "str", str: string }
, but not to a specific type. Therefore, xyz can still have the property str: string
.
To make type narrowing work in these examples, you need to use a type guard that can narrow down the type to a specific member of the union. For example, you can define a custom type guard function like this:
function isNum(obj: { num?: unknown }): obj is { num: number } {
return typeof obj.num === "number";
}
Then you can use this type guard in your code to narrow down the type of xyz:
const xyz: { num: number } | { str: string } = { num: 42 };
if (isNum(xyz)) {
xyz // { num: number }
}
Similarly, for the second example, you can define a type guard function like this:
function isNum(obj: { type?: unknown }): obj is { type: "num", num: number } {
return obj.type === "num";
}
Then you can use this type guard in your code to narrow down the type of xyz:
const xyz: { type: "num", num: number } | { type: "str", str: string } = { type: "num", num: 42 };
if (isNum(xyz)) {
xyz // { type: "num", num: number }
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论