javascript - 作为对象键访问时无法推断类型

标签 javascript typescript

给出以下示例:

type Dictionary = {
  [key: string] : string | undefined
}

function greet(name: string) {
  return 'Hello ' + name + '!';
}

function callGreetError(key: string, d: Dictionary) {
  if (typeof d[key] !== 'undefined') {
    return greet(d[key]) // TS Error: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.Type 'undefined' is not assignable to type 'string'.(2345)
  }
  return key + ' is not in dictionary';
}

function callGreetNoError(key: string, d: Dictionary) {
  const storedVal = d[key];
  if (typeof storedVal !== 'undefined') {
    return greet(storedVal) // Error goes away when value is stored in an external var.
  }
  return key + ' is not in dictionary';
}

我试图理解为什么在 callGreetErrorif block 内的 d[key] 类型未被推断为一个字符串,即使我明确告诉 TS 它不是未定义

为什么在 callGreetNoError 上将 d[key] 的值存储在外部变量 storedVal 上可以修复此错误。

最佳答案

基本上TS不会缩小computed property names的属性访问类型喜欢 key .

const d: Dictionary = {...};
const key = "foo";
const fooProp = d[key];

// using .length as string type check
d["foo"] !== undefined && d["foo"].length; // ✔
fooProp !== undefined && fooProp.length; // ✔
d[key] !== undefined && d[key].length; // error, possibly undefined

事实并非如此,因为 TS 进行了一些可变性检查并警告 d[key]在检查和使用之间,值可能会发生变化。例如,以下代码对于编译器来说完全没问题,但可能会在运行时抛出:

const testDict: Dictionary = {
  get foo() { return Math.random() > 0.5 ? "hey" : undefined }
};

function callGreetError(d: Dictionary) {
  // compiles fine, but throws error at run-time from time to time
  if (d["foo"] !== undefined) d["foo"].length
}
callGreetError(testDict)

允许使用 control flow 适当缩小变量范围,TS必须清楚地知道,你指的是什么属性:通过带点符号的属性访问d.foo或使用括号符号和文字,如 d["foo"]

const storedVal = d[key] 的“技巧”有效,因为 TS 推断出 storedVal 的变量类型成为string | undefined 。由于控制流分析通常基于变量,因此编译器现在可以更轻松地缩小范围storedVal支票 undefined

Playground

关于javascript - 作为对象键访问时无法推断类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60035357/

相关文章:

javascript - 使用(纯)Javascript 加载 CSS 时的优缺点

javascript - Controller 中的 $watch 不会触发将项目插入指令中的数组

javascript - 如何使用 vee-validate 和 vue-i18n 翻译字段名称

javascript - 将 TypeScript 变量暴露给 JS 全局范围(使用 webpack)

typescript - 在手写的 d.ts 文件中,如何从模块根目录中的一个命名空间公开函数?

reactjs - TypeScript + React <- 传递 props

javascript - 使用 jQuery 为嵌套列表元素添加计数类

javascript - 将 "this"与多个按钮一起使用

angular - 将参数传递给服务构造函数?

node.js - 是否有标准的 Typescript + Nodejs 服务器样板模板?