介绍

考虑以下示例:


const organization = {}
organization.name = "Logrocket"

                                                           


这段看似无害的代码在动态分配时会引发 TypeScript 错误 name到 organization目的。

将属性动态分配给对象时引发错误

中的此示例 请参阅TypeScript Playground 。

如果您是 TypeScript 初学者,这也许是正确的,混淆的根源是:看起来如此简单的东西怎么会在 TypeScript 中成为这样的问题?

TL;DR 的全部内容是,如果你不能在声明时定义变量类型,你可以使用 Record实用程序类型或对象索引签名来解决这个问题。 但在这篇文章中,我们将探讨问题本身,并努力寻找在大多数情况下都可以使用的解决方案。

跳跃前进:

  • 了解将属性动态分配给对象的问题
  • 解决问题
  • 解决方案 1:在声明时显式键入对象
  • 解决方案 2:使用对象索引签名
  • 解决方案 3:使用 Record实用类型

了解将属性动态分配给对象的问题

一般来说,TypeScript 在声明变量时确定变量的类型,并且该确定的类型不会改变,即在整个应用程序中始终保持不变。

此规则有一些例外情况,例如在考虑缩小类型或使用 any类型,但这是要记住的一般规则。

在前面的例子中, organization对象声明如下:


const organization = {}


没有明确的类型分配给 organization变量,所以 TypeScript 推断出一个类型 organization根据声明 {},即文字空对象。


超过 20 万开发人员使用 LogRocket 来创造更好的数字体验 了解更多 →


例如,如果您添加一个类型别名,您可以探索的类型 organization:


type Org = typeof organization


探索字面量对象类型

请在 TypeScript Playground 中查看。

然后,当您尝试引用 name支持这个空对象文字:


organization.name = ...


TypeScript 大喊。

类型 ' 上不存在属性 'name' {}‘

当您了解问题时,该错误似乎确实合适。

让我们解决这个问题。

解决问题

有很多方法可以在这里解决 TypeScript 错误。 让我们考虑这些:

解决方案 1:在声明时显式键入对象

这是推理的最简单的解决方案。 在您声明对象时,请继续输入它。 此外,为其分配所有相关值。


来自 LogRocket 的更多精彩文章:

  • 不要错过 The Replay 来自 LogRocket 的精选时事通讯
  • 了解 LogRocket 的 Galileo 如何消除噪音以主动解决应用程序中的问题
  • 使用 React 的 useEffect 优化应用程序的性能
  • 之间切换 在多个 Node 版本
  • 了解如何 使用 AnimXYZ 为您的 React 应用程序制作动画
  • 探索 Tauri ,一个用于构建二进制文件的新框架
  • 比较 NestJS 与 Express.js

type Org = {
    name: string
}

const organization: Org = {
    name: "Logrocket"
}


请在 TypeScript Playground 中查看。

这消除了任何意外。 您清楚地说明了此对象类型是什么,并在创建对象时正确声明了所有相关属性。

但是,如果必须 动态 添加对象属性,这并不总是可行的,这就是我们都在这里的原因。

解决方案 2:使用对象索引签名

有时,对象的属性确实需要在声明后一次添加。 在这种情况下,您可以使用对象索引签名,如下所示:


type Org = {[key: string] : string}
const organization: Org = {}
organization.name = "Logrocket"


请在 TypeScript Playground 中查看。

当时的 organization变量已声明,您可以继续并将其显式键入以下内容 {[key: string] : string}.

为了进一步解释语法,您可能习惯于具有固定属性类型的对象类型:


type obj = {
  name: string
}


但是,您也可以替换 name对于“变量类型”。

例如,如果你想定义任何字符串属性 obj:


type obj = {
 [key: string]: string
}


请注意,语法类似于您在标准 JavaScript 中使用变量对象属性的方式:


const variable = "name" 
const obj = {
   [variable]: "Freecodecamp"
}


TypeScript 等效项称为对象索引签名。 此外,请注意,您可以键入 key与其他原语:


// number 
type Org = {[key: number] : string}

// string 
type Org = {[key: string] : string}

//boolean
type Org = {[key: boolean] : string}


解决方案 3:使用 Record实用类型

这 Record实用程序类型 允许您限制其属性为的对象类型 Keys和属性值是 Type. 它具有以下签名: Record<Keys, Type>.

在我们的示例中, Keys代表 string和 Type, string也是。 这里的解决方案非常简洁,如下所示:


type Org = Record<string, string>

const organization: Org = {}

organization.name = "Logrocket"


除了使用类型别名,您还可以内联类型:


const organization: Record<string, string> = {}


使用 Record实用类型

请在 TypeScript Playground 中查看。

大师兄影视App,支持双端影视追剧,多源播放支持投屏!

结论

除了原语之外,您必须处理的最常见的类型可能是对象类型。   如果您需要动态构建对象,请利用 Record实用程序类型或使用对象索引签名来定义对象上允许的属性。

如果您想了解更多关于这个主题的信息,请随时 查看我 的备忘单,了解 Stack Overflow 上的七个最常见的 TypeScript 问题,或者向 我发送任何问题 。 干杯!

写了很多 TypeScript? 观看 我们最近的 TypeScript 聚会的录像,了解如何编写更具可读性的代码。

TypeScript 为 JavaScript 带来了类型安全。 类型安全和可读代码之间可能存在紧张关系。 观看录音,深入了解 TypeScript 4.4 的一些新功能。