网站搜索

TypeScript - 如何处理可能为未定义的值?


我正在尝试使用一个可选参数,如果在调用函数时未包含该参数,它会自动被赋值。

当我在函数的全局作用域中使用这个参数时,我没有收到任何来自 linter 的错误,问题出现在我尝试在 forEach 内使用它时(我只在那里尝试过)。

以下代码是发生情况的示例:

interface opts {
  optionalParam?: number
}

const func = (options: opts): void => {
  // I assign a value to the optional parameter
  options.optionalParam ??= 100

  const obj = {
    test: 8
  }
  obj.test = options.optionalParam * obj.test // ✅ It works perfect

  const objs = [{
    test: 6
  }]
  objs.forEach((obj) => {
    obj.test = options.optionalParam * obj.test // ❌ The object is possibly "undefined".ts(2532)
               ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ
  })
}

我不完全理解为什么在一个地方它被检测为未定义,而在另一个地方却没有。🤔

答案#1

TypeScript 无法区分

objs.forEach(callback) // code that works with options

和

doSomethingAsynchronous().then(callback) // code that works with options

在第二种情况下,为什么可能会出现问题应该很清楚——在异步代码运行之前,你可能会将一个未定义的值赋回给 optionalParam。(options.optionalParam=undefined;)——该属性的类型为 number | undefined。

第一个使用 forEach 的案例也有类似的问题,因为你正在处理一个回调。

一种方法是移除回调,并改用 for 循环。

for (const obj of objs) {
  obj.test = options.optionalParam * obj.test
}

另一种方法是将 optionalParam 提取到一个明确定义的变量中。

const func = (options: opts): void => {
  const optionalParam = options.optionalParam ?? 100;
  // proceed to reference optionalParam in the future
  // don't reference `options` again

或者,更简洁地说

const func = ({ optionalParam = 100 }: opts): void => {