解决这个问题的唯一方法是以不同的方式声明枚举。
执行此操作的一种方法非常冗长,但其行为很像声明的具有未知值的枚举。 TypeScript 中的真正枚举使用少量代码添加了许多命名类型和值,因此要手动模拟它,我们需要很多行。通用技术是为A、A.B、A.C 和A.D 中的每一个声明一个值和一个类型,并以将每个枚举值的类型视为不同的方式进行操作彼此不知道他们到底是什么:
declare namespace A {
interface _B { readonly __nominal: unique symbol; }
export type B = _B & number;
export const B: B;
interface _C { readonly __nominal: unique symbol; }
export type C = _C & number;
export const C: C;
interface _D { readonly __nominal: unique symbol; }
export type D = _D & number;
export const D: D;
}
type A = A.B | A.C | A.D;
在上面,{ readonly __nominal: unique symbol } 用作branding 技术,使用unique symbols 使TypeScript 将A.B、A.C 和A.D 中的每一个都视为名义上类型因此,尽管具有“相同”的结构,但类型却彼此不同。这有点对编译器撒谎,因为很明显在运行时 A.C 不会有一个名为 __nominal 的属性,但只要你忽略它,它应该会正常工作。
让我们确保:如果您有一个完整枚举类型的变量,您可以为其分配任何成员:
let a: A = A.B; // okay
a = A.C; // okay
a = A.D; // okay
但是如果你只有一个成员类型的变量,你不能分配其他的:
let b: A.B = A.B; // specifically only A.B
b = A.C; // error! A.C not assignable to A.B
b = A.D; // error! A.D not assignable to A.B
现在你的类型被允许了:
interface ISomeRestrictedProps {
restrictedProp: A.B | A.C;
}
并且表现得或多或少像你想要的那样:
const i: ISomeRestrictedProps = {
restrictedProp: A.B // okay
};
i.restrictedProp = A.C; // okay
i.restrictedProp = A.D; // error! D not assignable to B | C
Link to branded-enumlike code
同样,您可以执行 @TitianCernicova-Dragomir suggested 并为枚举赋值。它们不一定是 实际 值,只要它们彼此不同并且您不会错误地将它们视为实际值:
declare enum A {
B = 0xbbbbb, // dummy value for B
C = 0xccccc, // dummy value for C
D = 0xddddd // dummy value for D
}
再一次,你在对编译器撒谎关于确切的值,但只要你忽略确切的值并且不编写关心确切值的代码,应该没问题。后面的代码应该都如你所愿(我不会重复上面的代码……你可以在下面的链接中看到它是如何工作的)
Link to dummy-val-enum code
在这两种方法中,您都对编译器撒了一点谎……前一种方法很冗长,但不会假装您知道枚举的数值,而后一种方法更简单,但可能运行更多粗心的开发人员认为虚拟值是实际值的风险。
无论如何,希望对您有所帮助;祝你好运!