Mat*_*ead 1 undefined discriminated-union typescript type-narrowing union-types
谁能解释为什么 Typescript 可以使用in关键字缩小类型,但不能通过存在非未定义的值来缩小类型?我正在将一个大型代码库从 JS 移植到 TS,并且对该结构进行了非常广泛的使用if (x.something) { ... }。
declare const x: { a?: object } | { b: number };
if ('a' in x) {
const Q = x.a; // Q: object | undefined, correct but not very helpful - still have to test Q for non-undefined
}
if (x.a) {
const Q = x.a; // Doesn't work, but if it did, Q: object, which is helpful
}
if (typeof x.a !== "undefined") {
const Q = x.a; // Same as above
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果它不是联合体,它将按预期工作:
declare const x: { a?: object }
if ('a' in x) {
const Q = x.a; // Q: object | undefined, correct but not very helpful
}
if (x.a) {
const Q = x.a; // Q: object (yay!)
}
Run Code Online (Sandbox Code Playgroud)
问题
\n\n有一些规则需要记住:
\n\nif (x.a)错误 \xe2\x80\x94a没有在联合的第二个成员上定义。{ foo: string, bar: number }通常可以分配给 type { foo: string }。这就是为什么if (\'a\' in x)\xe2\x80\x94 任何具有名为 的属性的类型都a无法通过该检查的原因。但我们不能保证该值将是一个对象。假设它是不安全的。typeof x === "string". 类型保护有一个特殊的语法,告诉 TypeScript 缩小检查的类型。这就是为什么if (typeof x.a !== "undefined")在你的例子中不起作用的原因。解决方案
\n\n让您的工会独一无二。告诉 TypeScript 如果a存在,则b永远不会被定义,反之亦然。
declare const x: { a?: object, b?: undefined } | { b: number, a?: undefined }\nRun Code Online (Sandbox Code Playgroud)\n\n请注意,我们将不需要的属性标记为可选。相反,如果我们这样做{ a?: object, b?: undefined } | { b: number, a?: undefined },那么将需要不需要的属性,并且x必须将它们显式设置为undefined。
您现在可以使用这些方法来处理x.
function isDefined<T>(candidate: T | null | undefined): candidate is T {\n return candidate != null;\n}\n\nif (x.a) { \n const Q = x.a; // object\n}\n\nif (isDefined(x.a)) {\n const Q = x.a; // object\n}\n\nif (typeof x.a !== "undefined") { \n const Q = x.a; // object\n}\nRun Code Online (Sandbox Code Playgroud)\n\n请注意,您仍然无法使用使用运算符的方法in。这样做有一个很好的理由:它可以防止误报。只要我们不需要的属性的值显式设置为 ,就允许它们存在于对象上undefined。考虑以下示例:
function test(x: { a?: object, b?: undefined } | { b: number, a?: undefined }): void {\n if (\'a\' in x) {\n x.a; // object | undefined (good). We cannot expect object here.\n }\n}\n\ntest({ b: 1, a: undefined }); // "a" is not an object!\nRun Code Online (Sandbox Code Playgroud)\n\n提示:使用ExclusiveUnion助手
?undefined我们可以创建一个助手来为我们执行此操作,而不是将不需要的属性标记为。
declare const x: ExclusiveUnion<{ a?: object } | { b: number }>;\nRun Code Online (Sandbox Code Playgroud)\n\n执行:
\n\ntype DistributedKeyOf<T> =\n T extends any\n ? keyof T\n : never;\n\ntype CreateExclusiveUnion<T, U = T> =\n T extends any\n ? T & Partial<Record<Exclude<DistributedKeyOf<U>, keyof T>, never>>\n : never;\n\ntype ExclusiveUnion<T> = CreateExclusiveUnion<T>;\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
972 次 |
| 最近记录: |