我有多个枚举
const enum E1 {
CLOSED = 'CLOSED',
OPEN = 'OPEN',
IN_PROGRESS = 'IN_PROGRESS',
}
const enum E2 {
OPEN = 'OPEN',
CLOSED = 'CLOSED',
IN_PROGRESS = 'IN_PROGRESS',
}
const enum E3 {
OPEN = 'OPEN',
IN_PROGRESS = 'IN_PROGRESS',
}
我想创建一个接受枚举的函数,其中一个值应该是“CLOSED”
const func = (value: 'CLOSED') => {...}
interface Data1 {status: E1}
interface Data2 {status: E2}
interface Data3 {status: E3}
const o1: Data1 = {status: E1.CLOSED}
const o2: Data2 = {status: E2.OPEN}
const o3: Data3 = {status: E3.OPEN}
func(o1.status) // this should be valid. status is type E1, it contains 'CLOSED'
func(o2.status) // this should be valid. status is type E2, it contains 'CLOSED'
func(o3.status) // this should be invalid. status type is E3, it does not contain 'CLOSED'
但它会为每个对象引发一个错误:
Argument of type E... is not assignable to parameter of type "CLOSED"
我不希望该函数知道每个枚举,因为它们有很多。这就是为什么我使用类型value: 'CLOSED'
我是否需要像通用枚举这样的东西来让其他人以某种方式扩展它,以便我可以在参数中使用它的类型而不是“CLOSED”?
Typescript 版本:4.9.4
枚举具有一些奇怪的类型系统行为,这使其变得更加复杂。现在,我们只使用普通的字符串文字类型而不是枚举,然后我们就可以回到它。我们现在可以用
const
断言对象和类型别名E1
替换您的枚举定义。看起来像其它的也类似。
类型
(value: "CLOSED") => void
不适合您,因为这意味着您传入的任何东西都value
必须可分配给文字类型"CLOSED"
。这与您想要的正好相反。相反,您想说必须"CLOSED"
可分配给类型。您不想从上方value
限制类型(例如,它必须是或某种较窄的类型),而是想从下方限制它(例如,它必须是或某种较宽的类型)。value
"CLOSED"
"CLOSED"
不幸的是,TypeScript 本身并不支持这种下限类型约束。TypeScript 的约束(例如
T extends U
)是上限。microsoft /TypeScript#14520有一个开放功能请求,允许下限约束(例如T super U
)。如果这是 TypeScript 的一部分,那么我认为你可以写就完成了。你可以
value
从上方用进行约束string
,从下方用进行约束"CLOSED"
。但你不能直接这样做。作为一种解决方法,您可以利用约束中的条件类型
T super "CLOSED"
。从概念上讲,与相同"CLOSED" extends T
。因此,如果我们可以重写约束以"CLOSED" extends T
强制执行,那么它可能会按照您想要的方式运行:而且它确实有效。当您调用时
func(o1.status)
,T
推断为E1
。然后约束变为'CLOSED' extends E1 ? string : never
,它会折叠为string
,因此约束是T extends string
满足并且成功。但是当你调用 时
func(o3.status)
,T
被推断为E3
。那么约束就变成了'CLOSED' extends E3 ? string : never
,它会折叠为类型never
,因此约束就是 ,它T extends never
不满足并且会失败。如果您不使用枚举,我就会这样做。枚举使情况变得更加复杂,因为它们本身大多被视为其值的正确子类型
E1.CLOSED extends "CLOSED"
。所以是正确的,但"CLOSED" extends E1.CLOSED
错误的是:这意味着
"CLOSED"
不是 的下限,即使它是字符串文字类型E1
所代表的下限。我不会尝试剖析枚举,而是使用一个技巧将字符串枚举扩展为其字符串文字类型:只需使用模板文字类型来序列化它们:E1
"CLOSED"
的下限也是如此E1Serialized
。这意味着我们可以将func
其改为一切正常:
游乐场链接到代码
这对你有用吗?
查看此演示