never 的妙用
2023-08-02 21:09:06
never 在 ts 中表示不存在的类型,并且 never 类型仅能被赋值给另外一个 never
类型穷举检查
我们先来看这段代码
ts
type Method = 'GET' | 'POST'
function request(method: Method, url: string) {
switch (method) {
case 'GET':
return '123'
case 'POST':
return '456'
default:
method
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
这是一段很常见的代码,根据不同的方法执行不同的请求,因为前面两种情况已经把 method 的所有可能分支都穷举出来了,永远不会进入到 default,所以这里的 method 被类型收缩成了 never
但是当我们为 Method 添加了一个新的类型后,而我们没有对新添加的类型做分支处理,那么这段代码就会有些问题了
ts
type Method = 'GET' | 'POST' | 'PUT'
function request(method: Method, url: string) {
switch (method) {
case 'GET':
return '123'
case 'POST':
return '456'
default:
method
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
我们为 Method 添加了一个类型 PUT,此时的 method 类型被收缩为 PUT,这就说明我们没有为 PUT 类型做分支处理,所以我们可以稍微处理下这里的代码
ts
type Method = 'GET' | 'POST' | 'PUT'
function request(method: Method, url: string) {
switch (method) {
case 'GET':
return '123'
case 'POST':
return '456'
default:
const val: never = method // error
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
此时我们发现第 10 行代码这里的 val 会报错,不能将 string 类型分配给 never,这是因为 never 类型只能分配给 never 类型,而由于我们没有为 method 做新的分支处理,导致 method 类型被收缩为 PUT,所以这里就会给我们报错提醒,让我们尽早的发现错误
类型取反(禁用类型)
我们平时使用 ts 最经典的场景都是为了约束传参,比如限制函数传参类型为数字或者字符串,我们可以通过 never 来对约束类型取反,比如限制传参为除了字符串其他类型传什么都可以,相当于禁用了字符串类型
我们来写个函数,让这个函数传参限制为除了字符串其他的类型都可以
ts
type banType<T, K> = T extends K ? never : T
function foo<T>(params: banType<T, string>) {
return params
}
foo('Hello') // error
foo(123)
foo({})
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
这里通过使用 never 来实现,传入了 string 类型和参数的类型,会用参数类型来进行判断是不是 string 类型,是的话会返回 never 类型,而 never 类型只能赋值给其他类型,所以这里就会报错,不是的话就直接返回参数的类型,这样就实现了一个类型取反、禁用类型的方法