TypeScript报错:Object is possibly “null“ 解决方法——断言函数

学习一些博客的笔记。
原文:Assertion Functions in TypeScript — Marius Schulz
TS系列:TypeScript Evolution — Marius Schulz

如果很急,可以直接看 文章目录:省流结论。

断言函数是一种对类型系统的支持。

TypeScript 3.7 implemented support for assertion functions in the type system.

举个例子,我们想拿到一个id为root的节点,并给它添加点击事件:

const root = document.getElementById("root");

root.addEventListener("click", e => {
    
    
  /* ... */
});

此时TS会报错Object is possibly null。因为root是HTMLElement | null,而null是没有办法添加点击事件的。因此,我们在添加点击事件前需要保证root是非空 null非未定义 undefined的。

我们有3种方法。

方法1:使用非空断言运算符!

非空断言运算符:!,告诉TS假定root是非空非未定义。

const root = document.getElementById("root")!;

root.addEventListener("click", e => {
    
    
  /* ... */
});

root原本的类型是HTMLElement | null,使用了!后忽视了null,TS会只把他当作HTMLElement

然而, 使用非空断言!并不是这种情况的正确解决方法 。原因是:!运算符编译成JS后会自动消失,TS代码不会去判断root是否是null。此时若root是null,还是会报错(没法添加点击事件)。

方法2:内联空检查

先判断root是否为空。

const root = document.getElementById("root");

// 这里的root是 HTMLElement | null

if (root === null) {
    
    
  throw Error("Unable to find DOM element #root");
}

// 这里的root是 HTMLElement

root.addEventListener("click", e => {
    
    
  /* ... */
});

这种方法不包含任何特定于TypeScript的语法;以上所有都是语法上有效的JavaScript。

方法3:实现断言函数

如果value是null或undefined,就抛出异常。

function assertNonNullish(
  value: unknown,
  message: string
) {
    
    
  if (value === null || value === undefined) {
    
    
    throw Error(message);
  }
}

但是:

const root = document.getElementById("root");

// Type: HTMLElement | null
root;

assertNonNullish(root, "Unable to find DOM element #root");

// Type: HTMLElement | null
root;

// 还是报错:TS认为这里的root还是有可能是null
root.addEventListener("click", e => {
    
    
  /* ... */
});

TS并不知道我们的断言函数assertNonNullish已经过滤掉了root是null或undefined的情况。我们需要 显式地 让TS知道此函数assertNonNullish是断言函数,它断言的值是非null/undefined的。我们可以在返回类型中写关键字:

function assertNonNullish<TValue>(
  value: TValue,
  message: string
): asserts value is NonNullable<TValue> {
    
    
  if (value === null || value === undefined) {
    
    
    throw Error(message);
  }
}

其中,asserts value is NonNullable<TValue> 是一个断言签名,它表示:如果函数正常返回(即,没有抛出错误),则value参数的类型是非空的<TValue>(这里的<TValue>是泛型)。TS可以用此信息来缩小传递给value参数的表达式的类型。

缩小类型了:

const root = document.getElementById("root");

// Type: HTMLElement | null
root;

assertNonNullish(root, "Unable to find DOM element #root");

// Type: HTMLElement
root;

root.addEventListener("click", e => {
    
    
  /* ... */
});

NonNullable<T>

是一种条件类型:

/**
 * Exclude null and undefined from T
 */
type NonNullable<T> = T extends null | undefined ? never : T;

把T中的null和undefined去掉了。

如:

  • NonNullable<HTMLElement>HTMLElement
  • NonNullable<HTMLElement | null | undefined>HTMLElement
  • NonNullable<null | undefined>never

省流结论

function assertNonNullish<TValue>(
  value: TValue,
  message: string
): asserts value is NonNullable<TValue> {
    
    
  if (value === null || value === undefined) {
    
    
    throw Error(message);
  }
}

const root = document.getElementById("root");
assertNonNullish(root, "Unable to find DOM element #root");

root.addEventListener("click", e => {
    
    
  /* ... */
});

猜你喜欢

转载自blog.csdn.net/karshey/article/details/134265992