Typescript 如何避免折叠已包装的联合类型

Typescript 如何避免折叠已包装的联合类型,typescript,union-types,Typescript,Union Types,在我看来,当Typescript碰巧知道初始值时,它正在折叠一个不需要的包装联合类型。我不确定这是否是一个bug,但我想知道是否有办法避免它 例如: type Prime = 3|5|7; type OrDonuts<T> = T | 'donuts'; function compare<T>(a: T, b: OrDonuts<T>) { return a == b; } let value: Prime; compare(value, 3);

在我看来,当Typescript碰巧知道初始值时,它正在折叠一个不需要的包装联合类型。我不确定这是否是一个bug,但我想知道是否有办法避免它

例如:

type Prime = 3|5|7;
type OrDonuts<T> = T | 'donuts';

function compare<T>(a: T, b: OrDonuts<T>) {
    return a == b;
}

let value: Prime;
compare(value, 3);
// OK!

value = 5;
compare(value, 3);
// TS2345: Argument of type '5' is not assignable to parameter of type 'OrDonuts<3>'
为了避免这个错误,我必须通过将value=5表示为Prime;,来显式地解压

这是一个错误,预期的行为,我只是做错了吗


节点:10.15,类型脚本:3.5.1

它是的预期行为。宣布

type Prime = 3|5|7; // it is either 3 OR 5 OR 7 but never all of them at the the same time
告诉ts编译器Prime是其中一个值。现在,为键入的字段值指定5

或者如果您想以更通用的方式满足compare函数参数,如

let test = 5;
compare(test, 3); // <T> is now number which 5 and 3 are.

TypeScript类型检查器执行,这意味着它努力确定在运行时变量内部的值会发生什么变化,并将缩小这些变量的类型以进行匹配。发生这种情况的一种特殊方式是,如果您有a的变量或属性,并且编译器看到您为其指定了一个更具体的类型化值,那么它会将变量的类型缩小为该更具体的类型,至少在您为变量指定不同的值之前是这样

这通常是可取的,因为它支持这样的用例:

let x: number | string = Math.random() < 0.5 ? "hello" : "goodbye"; // x is string now
if (x.length < 6) { // no error here
  x = 0; // the widest x can be is string | number, so this assignment is fine
}
或者,您可以在要比较的调用中手动指定泛型类型T,这也适用于:

let value4: Prime = 5;
compare<Prime>(value4, 3); // okay
您可以使用这些选项中的任何一个

我能找到的最规范的文档来源是,特别是

好吧,希望这会有帮助;祝你好运


现在将5指定给未键入的字段值,这非常好。值不是非类型化的。它的let值为:Prime;。它就在OK示例的上面,但是值被声明为素数;它不是没有类型的。之所以会发生这种情况,是因为在赋值时,联合类型变量的范围缩小了,这通常是可取的。@jcalz更新了它。这个答案仍然没有解决问题中的问题。。。请参阅我上述评论中的链接;显式注释的变量被视为更窄的类型。这是预期的行为,但与类型推断无关也请注意,这个词是推断,而不是干扰,尽管我可以理解为什么一个沮丧的开发人员可能会使用后一个术语@jcalz^^^一些评论值得多次投票,很遗憾,我不会这么做-使您的示例更难理解的一个小问题是,第一个调用有一个错误,并且值未初始化。您可以使用declare来绕过这一点,而不在代码中为其赋值,从而触发您遇到问题的缩小。既然编译器告诉您不需要调用比较,那么也可以使用false,为什么在使用文本值时它会像这样缩小值呢?这是静态分析的好处之一。尽管我正在寻找一个关于在赋值时缩小联合类型变量的规范引用。收窄通常是需要的,但在您的情况下,它会导致意外的行为。如果你想禁用缩小,你必须做let-value:Prime=5作为Prime或let-value=5作为Prime。好的,这是规范问题。感谢addl链接,我同意这种行为是有益的,而不是有害的。导致一些意想不到的副作用,比如说,jasmine打字(如预期),但解决方法非常简单,因为我知道这是预期的。它真的是5型吗?因为如果你试图给它赋值1,它会抱怨它不是Prime类型。它是控制流分析。如果编译器看到您为[union type variable]指定了一个更具体的类型值,它会将变量的类型缩小为更具体的类型,至少在您为变量指定不同的值之前是这样。我不知道你在问什么。。。为什么允许您将类型1的值赋给类型Prime的变量?编译器不会完全忘记变量的注释类型;它只是将该值视为缩小类型。
let x: number | string = Math.random() < 0.5 ? "hello" : "goodbye"; // x is string now
if (x.length < 6) { // no error here
  x = 0; // the widest x can be is string | number, so this assignment is fine
}
let value2: Prime = 5 as Prime
compare(value2, 3); // okay

let value3: Prime = 5;
compare(value3 as Prime, 3); // okay
let value4: Prime = 5;
compare<Prime>(value4, 3); // okay