与Typescript中可能的类型文字进行匹配

与Typescript中可能的类型文字进行匹配,typescript,pattern-matching,Typescript,Pattern Matching,以下面的例子为例: type BinaryOp = 'MOV' type UnaryOp = 'ADD' | 'SUB' | 'JRO' const BinaryOps: BinaryOp[] = ['MOV'] const UnaryOps: UnaryOp[] = ['ADD', 'SUB', 'JRO'] type Line = { op: BinaryOp, a: number, b: number } | { op: UnaryOp, a: number } 以及以下“

以下面的例子为例:

type BinaryOp = 'MOV'
type UnaryOp = 'ADD' | 'SUB' | 'JRO'
const BinaryOps: BinaryOp[] = ['MOV']
const UnaryOps: UnaryOp[] = ['ADD', 'SUB', 'JRO']

type Line =
    { op: BinaryOp, a: number, b: number }
  | { op: UnaryOp, a: number }
以及以下“模式匹配”:

我并不特别喜欢这样,为了让案例理解op是
UnaryOp
还是
BinaryOp
,我必须列举所有的可能性。有没有一个紧凑的(er)方法来实现这一点


注意。考虑到这是一个简化的示例,可能还有其他类型的
Op

我不认为有任何类型脚本技巧可以用来避免枚举所有的
大小写
标签,因为标签必须是值,而不是类型

但是,可以使用
if
语句而不是
开关
,并且可以在
if
表达式中使用

用户定义的类型保护是一个返回类型为类型谓词的函数。例如,
UnaryOp
的用户定义类型保护可能如下所示:

function isUnaryOp(op: string): op is UnaryOp {
  return op && UnaryOps.includes(op as any);
}
if
语句中使用时,用户定义的类型保护将缩小类型:

if (isUnaryOp(line.op)) {
  const op = line.op; // Inferred to be UnaryOp
} else if (isBinaryOp(line.op)) {
  const op = line.op; // Inferred to be BinaryOp
} else {
  const op = line.op; // Inferred to be never
}

这是一个极小的例子
default
在这种特殊情况下可以工作,但它在语义上并不等价。放弃
switch
语句而使用调用的
if
else if
语句将是解决问题的一种方法。@cartant事实上,我就是这样解决的,谢谢:)想回答这个问题以便我能接受吗?事实上,我们可以将
isSomething
助手推广到
导出函数is(op:U,collection:Array):op是T{return collection.includes(op as T)}
@hugoseronenoreferreira我是否可以建议一种方法来确保并集和数组保持同步
if (isUnaryOp(line.op)) {
  const op = line.op; // Inferred to be UnaryOp
} else if (isBinaryOp(line.op)) {
  const op = line.op; // Inferred to be BinaryOp
} else {
  const op = line.op; // Inferred to be never
}