假设我有一个条件列表,我想处理
type
的每个可能值。如果我将来添加了一个新的 type
并且忘记处理它,我想要一个错误 - 至少是一个运行时错误,但理想情况下是一个编译器错误,这样我就可以在部署之前发现我的错误。
如何断言变量的类型为
never
?
type Job = { type: 'add'; payload: any } | { type: 'send'; payload: any }
const handleJob = (job: Job) => {
const add = (job: Job) => {
console.log(job)
}
const send = (job: Job) => {
console.log(job)
}
if (job.type === 'add') {
add(job)
} else if (job.type === 'send') {
send(job)
} else {
// `job` is actually type `never` here,
// this error won't ever be thrown unless additional strings are added to the `Job.type` schema.
throw new Error(`Unhandled job.type "${(job as Job).type}".`)
}
}
never
返回函数,它只接受 never
类型的参数,这意味着编译器只有在实际上不希望调用该函数时才会感到高兴。这个函数通常被称为assertNever()
。这是一种写法:
function assertNever(x: never, msg?: string): never {
throw new Error(msg ?? "unexpected value " + String(x));
}
如果它确实被调用,那么您将收到运行时错误。现在以下内容按预期编译:
if (job.type === 'add') {
add(job)
} else if (job.type === 'send') {
send(job)
} else {
assertNever(job, // <-- okay
`Unhandled job.type "${(job as Job).type}".`
);
}
但是如果我们添加新的工作类型:
type Job =
{ type: 'add'; payload: any } |
{ type: 'send'; payload: any } |
{ type: 'explode' }; // add this
现在失败了,也正如预期的那样:
if (job.type === 'add') {
add(job)
} else if (job.type === 'send') {
send(job)
} else {
assertNever(job, // error!
// -----> ~~~
// Argument of type '{ type: "explode"; }' is
// not assignable to parameter of type 'never'.
`Unhandled job.type "${(job as Job).type}".`
);
}
if
/else
语句。