首页 > 解决方案 > 打字稿:空值检查在 array.map 函数中不起作用

问题描述

为什么我之前在 map 函数之前检查的可为 null 类型在 map 中不起作用?

function x() {
  let y: number | null;
  y = null;

  if (!y) {
    return [];
  }

  return [1, 2, 3, 4].map((z) => {
    // error: y cannot be null
    return z + y;
  })
}

TypeScript Playground 上的代码

标签: typescripttypescript-typings

解决方案


由于您使用的是类型保护let而不是const类型保护,因此不能保证您不会修改该值,也就是说 TS 采用了关于类型 ( number | null) 的原始假设,您需要再次检查它。改变yconst帮助。

重新分配 y 的示例

考虑到您可能在检查后,再次设置ynull.

function x(defValue: number | null) {
  let y = defValue;
  if (!y) {
    return [];
  }
  // and below the change even though we checked that before the check is not safe
  y = null;
  return [1, 2, 3, 4].map((z) => {
    // no error
    return z + y;
  })

}

我如何更改值的另一个示例是 - 在地图本身中,请考虑:

return [1, 2, 3, 4].map(z => {
    y = null // changed to null!!
    return z;
  }).map((z) => {
    // error as it can be null
    return z + y;
  })

它不安全检查的主要原因是我们不能说回调何时会被调用,我们在这个范围内声明它的事实并不意味着它会同时执行,例如,如果它会Promise.then,执行时间是未知的。考虑这样的代码:

function x(defValue: number | null) {
  let y = defValue;
  if (!y) {
    return [];
  }
  httpClient.get('http://something').then((z: number) => {
    // error correctly because y is null
    return z + y;
  });

  y = null; // this code is executed before then
}

另一个例子是暴露y外部可能发生的变化。考虑:

function x(defValue: number | null) {
  let y = defValue;
  if (!y) {
    return null
  }
  return {
    f: (z: number) => z + y, // error as y can be null because yToNull can change it
    yToNull: () => { y = null } // modify the y to null
  }
}
const fg = x(1);

if (fg) {
  fg.yToNull();
  fg.f(2); // y is null inside the scope of f
}

使用 const 进行持久保护

如您所见,let在整个闭包中将变量视为由守卫缩小是非常不安全的。

使用const这种重新分配是不可能的,并且 TS 能够推断出闭包范围内的值的窄类型。

function x(defValue: number | null) {
  const y = defValue;
  if (!y) {
    return [];
  }
  // any change of y type is not possible with const
  return [1, 2, 3, 4].map((z) => {
    // no error as y cannot be re-assigned
    return z + y;
  })

}

推荐阅读