是否可以检测到不必要的类型防护?



我有以下打字稿代码:

type Nothing = undefined | null;
export const isNothing = <T>(val: T | Nothing): val is Nothing =>
val === null || typeof val === 'undefined';

isNothing是一个类型保护,基本上检查是否设置了值。

我想在运行时之前检测以下内容:

const foo:number = 42;
if(isNothing(foo)) { /* ... */ }

这里的情况是类型保护是多余的。由于foo是显式类型的,因此不能nullundefined

我一直试图按照以下思路找到答案:

  • 重载isNothing以返回类型never(如果不是联合类型val则返回类型
  • 一些 linter 规则,当采用联合的函数的参数不是联合时标记(这感觉像是大锤方法(。
  • 一些显式检测不必要的类型保护的 linter 规则

在这种情况下,"检测"要么是编译时错误,要么是 linter 通知。重要的是,这将是运行时前检测。

正如我在上面的评论中所解释的,没有这样的解决方案,如果检查是多余的,类型保护本身会阻止代码编译。我认为术语"类型联合"是指在这种特殊情况下,变量不是空的,也不是未定义的,因此isNothing类型保护检查将是多余的。

一种解决方案是强制编译器在调用isNothing类型保护之前检查变量是否"可能为 null 或未定义":

type Nothing = undefined | null;
export const isNothing = <T>(val: T | Nothing): val is Nothing =>
val === null || typeof val === 'undefined';

let a!: number;
let b!: number | undefined;
let c!: undefined;
let d!: null;
function assertMaybeNothing<T extends (Exclude<T, Exclude<T, undefined | null>> extends never ? never : any)>(arg1: T) {
return true;
}
assertMaybeNothing(a); // error because is never undefined or null
assertMaybeNothing(b);
assertMaybeNothing(c);
assertMaybeNothing(d);
if (assertMaybeNothing(a) && isNothing(a)) {
let x = a;// is never
} 

游乐场链接

我最终选择了这个:

type Nothing = undefined | null;
export function isNothing<T>(val: NonNullable<T>): never
export function isNothing<T>(val: T | Nothing): val is Nothing
export function isNothing<T>(val: T) { return val === null || typeof val === 'undefined'; }

然后,我将strict-boolean-expressions设置为在 TSLint 配置中true

因此,每当将不包含nullundefined的显式类型的变量传递给此函数时,我的 linter 就会捕获。

最新更新