即使在未定义检查之后,打字稿“错误 TS2532:对象可能是‘未定义’”

Posted

技术标签:

【中文标题】即使在未定义检查之后,打字稿“错误 TS2532:对象可能是‘未定义’”【英文标题】:Typescript "error TS2532: Object is possibly 'undefined'" even after undefined check 【发布时间】:2018-09-11 15:23:01 【问题描述】:

我正在尝试在tsc 上使用--strict 选项,但遇到了以下我似乎无法理解的“奇怪”案例。

如果我写:

function testStrict(input: query?: [prop: string]: string) 
  if (input.query) 
    Object.keys(input.query).forEach(key => 
      input.query[key];
    )
  
  return input;

编译器抱怨:

test.ts(5,9):错误 TS2532:对象可能是“未定义”。

(违规行是input.query[key];

我不明白的是,我已经在函数if (input.query) 的第一行使用 if 守卫检查了 undefined,所以 为什么编译器认为它可能是 undefined?

我通过在对象访问之前添加另一个相同的保护来解决此问题,例如:

function testStrict(input: query?: [prop: string]: string) 
  if (input.query) 
    Object.keys(input.query).forEach(key => 
      if (input.query) 
        input.query[key];
      
    )
  
  return input;

但我不明白为什么需要另一条相同的行。

【问题讨论】:

虽然这对于同步运行的forEach 没有意义,但在一般情况下,当我们考虑回调函数时,它确实有意义。如果您传递的那个函数是一个回调函数,那么它可能直到将来某个时候才会被调用,到那时input 对象可能已经改变(input.query 可能已经变得未定义)。所以 TS2532 在处理回调时帮助我们免于被枪杀。 Titian 的解决方案不仅满足 TypeScript,而且还防止了特定错误的发生。 (通过保留对原始 query 对象的引用。) 【参考方案1】:

因为对input.query 的第二次访问发生在另一个函数内部,所以箭头函数传入forEach。流分析不跨越函数边界,因此由于您处于另一个函数中,因此您需要再次测试。

双重测试的替代方法是使用局部变量,因为变量的类型在赋值时被锁定,并且不包括 undefined 类型:

function testStrict(input:  query?:  [prop: string]: string  ) 
    if (input.query) 
        const query = input.query;
        Object.keys(input.query).forEach(key => 
            query[key];
        )
    
    return input;

【讨论】:

如果您将let query 替换为const query,效果会更好

以上是关于即使在未定义检查之后,打字稿“错误 TS2532:对象可能是‘未定义’”的主要内容,如果未能解决你的问题,请参考以下文章

为自定义打字稿错误实例实施 instanceof 检查?

使用打字稿进行反应组件子类型检查

打字稿:如何检查一个值是不是是有效的枚举键值? [复制]

如何故意在打字稿中定义一个“空接口”

即使使用 if 语句,对象也可能未定义

在自定义输入元素上使用带有打字稿的 useRef