gpt4 book ai didi

TypeScript 字符串并集不能分配给函数中的元组并集

转载 作者:搜寻专家 更新时间:2023-10-30 21:25:43 26 4
gpt4 key购买 nike

这两个示例的行为应该相同,但第二个示例出错。为什么?

// Example 1:
const a: 'x' | 'y' = 'x';
const b: ['x'] | ['y'] = [a]; // ok

// Example 2:
function fn(a: 'x' | 'y') {
const b: ['x'] | ['y'] = [a];
// ^
// Type '["x" | "y"]' is not assignable to type '["x"] | ["y"]'.
// Type '["x" | "y"]' is not assignable to type '["x"]'.
// Type '"x" | "y"' is not assignable to type '"x"'.
// Type '"y"' is not assignable to type '"x"'.
}

您可以 try it on the playground .

最佳答案

更新:2019-05-30 TypeScript 3.5 版本引入了 smarter union type checking它针对对象类型(如 {a: "x"} | {a: "y"} 修复了此问题,但似乎对元组类型(如 ["x "] | ["y"])。不确定这是不是故意的。


在“示例 1”中,a 被初始化为 "x" 这一事实产生了很大的不同。控制流分析将 a 的类型缩小为 "x",尽管您的注释为 "x"| “y”:

let a: "x" | "y" = "x";
console.log(a === "y"); // error!
// This condition will always return 'false'
// since the types '"x"' and '"y"' have no overlap.

那么当然在这种情况下 [a] 将匹配 ["x"] | ["y"],因为 [a] 被编译器识别为 ["x"] 类型。


因此,示例 1 只是巧合地成功了。一般来说,这会失败。编译器一般看不到[A] | [B] 等同于 [A | B]。前者被视为比后者更窄的类型。

type Extends<T, U extends T> = true;
type OkayTup = Extends<[string | number], [string] | [number]>;
type NotOkayTup = Extends<[string] | [number], [string | number]>; // error!

这可能令人惊讶,因为实际上每个 [A | B] 应该可以分配给类型 [A] | [B]。当您查看类似的 property-bag 版本时,同样的惊喜会发生:

type OkayObj = Extends<{a: string | number}, {a: string} | {a: number}>;
type NotOkayObj = Extends<{a: string} | {a: number}, {a: string | number}>; // error!

同样,{a: A} | {a: B} 被视为比 {a: A | 更窄的类型B},尽管事实上您很难想出不能分配给前者的后一种类型的值。

那么,这里发生了什么?好吧,这似乎是 intentionaldesign limitation typescript 。 Word of Language Architect说:

For your example to type check with no errors we would have to consider types of the form { x: "foo" | "bar" } to be equivalent to { x: "foo" } | { x: "bar" }. But this sort of equivalence only holds for types with a single property and isn't true in the general case. For example, it wouldn't be correct to consider { x: "foo" | "bar", y: string | number } to be equivalent to { x: "foo", y: string } | { x: "bar", y: number } because the first form allows all four combinations whereas the second form only allows two specific ones.

(注意:等价性在比上面提到的稍微多一些的情况下成立......它仅适用于每个联合成分中不同的属性在单个联合中采用联合的所有可能值的情况-property case. 所以,{x: string | number, y: boolean, z: string} 等价于 {x: string, y: true, z: string} | {x : string, y: false, z: string} | {x: number, y: true, z: string} | {x: number, y: false, z: string})

我想说这是一个设计限制......检测相对罕见的属性联合可以折叠/扩展的情况将非常昂贵,而且不值得实现。


在实践中,如果您发现自己面临编译器未验证但您知道是安全的联合属性合并问题,请展示您的卓越智慧和 assert你的出路:

function fn(a: 'x' | 'y') {
const b = [a] as ['x'] | ['y'] // I'm smarter than the compiler 🤓
}

好的,希望对你有帮助;祝你好运!

关于TypeScript 字符串并集不能分配给函数中的元组并集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56174696/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com