在本文中,我们将学习如何通过组合类型运算符和枚举来提取和声明常量类型typeof
,以使您的代码库得到优化。keyof
先决条件
为了获得更好的编码体验,您应该在 IDE 中安装 TypeScript,例如VSCode。它将为您提供许多基本功能,例如错误突出显示、IntelliSense、linting 等...您还应该安装一些扩展,例如JavaScript 和 TypeScript Nightly、ESLint等。
什么是typeof
在 TypeScript 中,我们可以用来typeof
提取变量或属性的类型,如下例所示:
``` const Name = { firstName: 'Maya', lastName: 'Shavin' };
let myName: typeof Name; ```
在上面的代码中,我们使用myName
从变量 中提取的类型来声明变量Name
,这将是一个具有两个属性 -firstName
和 的对象lastName
。当鼠标悬停myName
在 IDE 中时,TypeScript 将向您显示myName
结论的类型Name
,如以下屏幕截图所示:
这里注意typeof
,如果要提取类型的变量是一个 Object,那么接收到的类型将是一个完整的类型结构,并且每个属性都有其类型(例如 type of 将有myName
两个字段 - firstName
of typestring
和lastName
of kind string
)。
另一个有价值的场景typeof
是将其与ReturnType
从函数中提取返回数据的类型结合起来。为此,我们执行以下操作:
- 使用以下方法获取声明函数的函数类型
typeof
- 使用
ReturnType<T>
withT
是步骤 1 中提取的类型来获取 from 的返回值类型T
。
下面的例子演示了如何提取返回类型decoupleName()
``` function decoupleName (name: string) { const [firstName, ...remaining] = name.split(" ");
return {
firstName,
lastName: remaining.reduce((text, word) => text ? `${text} ${word}` : word, '')
}
}
type NameObj = ReturnType ```
TypeScript 将自动引用正确的类型NameObj
,如下面的屏幕截图所示:
此外,我们可以typeof
在 TypeScript 中用作条件块内的类型保护,就像在 JavaScript 中一样,尽管在这种情况下,它主要适用于string
、object
、function
等基本类型...
现在我们了解了typeof
它的用法。接下来我们就来探讨一下keyof
。
理解keyof
虽然typeof
生成由变量表示的类型,但keyof
采用对象类型并生成作为该变量键的自由联合的类型,如下所示:
``` interface User { firstName: string; lastName: string; };
type UserKeys = keyof User ```
以上等同于以下声明:
type UserKeys = "firstName" | "lastName"
但是,与 不同的是typeof
,您不能keyof
直接在变量上使用。对于以下代码,TypeScript 将引发错误:
``` const Name = { firstName: 'Maya', lastName: 'Shavin' };
type NameKeys = keyof Name; //error ```
要从对象变量(例如常量值的对象映射)中提取类型,我们需要结合keyof
和typeof
,我们接下来将学习这一点。
从对象的键(或属性)中提取typeOf
以下面的ImageVariables
为例,它充当修改图像时使用的变量的映射:
export const ImageVariables = { width: 'w', height: 'h', aspectRatio: 'ar', rotate: 'a', opacity: 'o', } as const;
请注意,这里我们需要const
对象末尾的 来将其指示为只读。否则,TypeScript 将不允许我们从中提取类型,因为存在随时修改对象内部属性的风险。
ImageVariables
包含从其键到根据Cloudinary 机制转换图像时使用的匹配变量符号的映射。要根据 的属性(或键)生成类型ImageVariables
,我们执行以下操作:
ImageVariables
获取代表使用的类型typeof
type ImageVariablesType = typeof ImageVariables
- 根据类型的键提取新类型
ImageVariablesType
,使用keyof
type ImageFields = keyof ImageVariablesType
或者,我们可以将上述两个步骤合二为一,如下所示:
type ImageFields = keyof typeof ImageVariables
就是这样。我们现在有了ImageFields
type,其中包含 的接受字段ImageVariables
,如下面的屏幕截图所示:
我们现在可以使用这个生成的类型,如下所示:
``` const transformImage = (field: ImageFields) => { const variable = ImageVariables[field]
//do something with it
} ```
通过基于 的属性声明类型ImageVariables
,任何使用 的流程transformImage
都是安全的,并且我们可以确保field
传递的内容始终需要存在于 中ImageVariables
。否则,TypeScript 将检测任何错误并向用户发出警报。
此外,Intellisense 将告知用户可接受的值,限制传递错误值的可能性。
顺便说一句,类型检查的行为与hasOwnProperty()
运行时检查类似,尽管它只发生在编译时。
听起来很简单。如果我们想将键的值提取到ImageVariables
新类型中怎么办?我们接下来看一下。
从对象的键(或属性)的值中提取typeof
如果我们想从 的键值生成一个类型ImageVariables
,我们可以执行以下操作:
type VariableValues = typeof ImageVariables[ImageFields]
由于我们已经声明ImageVariablesType
为 of 类型ImageVariables
,因此我们可以将上面的内容重写为:
type VariableValues = ImageVariablesType[ImageFields]
通过上面的代码,我们现在有了一个新类型,VariableValues
它接受以下值:
从命名常量对象的值和键生成类型在许多情况下都是有利的,例如当您必须使用各种数据映射并且标准键或值在它们之间进行映射时。在对象映射上使用keyof
和typeof
可以帮助创建相关映射和类型之间的连接,从而避免潜在的错误。
或者,我们可以结合枚举 和typeof
来实现相同的目标。
使用枚举
枚举是声明命名常量类型的一种方便且有组织的方式。它允许我们创建一组不同的常量值,并且每个枚举字段都是基于数字或基于字符串的。我们可以重写我们ImageVariables
的如下:
enum EImageVariables { width = 'w', height = 'h', aspectRatio = 'ar', rotate = 'a', opacity = 'o', }
使用枚举的优点之一是我们可以使用枚举的名称作为接受值声明的类型。因此,代替以下代码:
``` type VariableValues = typeof ImageVariables[ImageFields]
function transform(value: VariableValues) { //perform something } ```
EImageVariables
我们可以使用如下方式重写:
function transform(value: EImageVariables) { //perform something }
对于更少的代码,类型检查执行相同的操作。尽管如此,为了从声明的 enum 的键(或属性)获取类型,我们仍然需要像常规常量对象一样EImageVariables
使用组合:keyof typeof
type ImageFields = keyof typeof EImageVariables
就是这样。上面的代码产生的结果与我们使用ImageVariables
.
现在让我们回顾一下如何从常量对象的键和值获取类型:
``` export const ImageVariables = { width: 'w', height: 'h', aspectRatio: 'ar', rotate: 'a', opacity: 'o', } as const;
type ImageVariablesType = typeof ImageVariables; type ImageFields = keyof ImageVariablesType; type VariableValues = ImageVariablesType[ImageFields]; ```
与使用枚举相比:
``` enum EImageVariables { width = 'w', height = 'h', aspectRatio = 'ar', rotate = 'a', opacity = 'o', }
type EImageVariablesType = typeof EImageVariables; type EImageFields = keyof EImageVariablesType; //No need for getting the type of values ```
与常量对象一样,我们可以直接使用枚举键的值,例如EImageVariables.width
在我们的代码中。在运行时,枚举作为 JavaScript 对象存在于编译后的代码中,并且表现得像 JavaScript 对象。
一般来说,枚举是可以的。在 TypeScript 中,由于其实现方式效率低下(希望这个问题已得到修复或会很短),许多人认为它对性能有影响。
那么我们应该使用它们吗?这取决于。这个选择由你。
概括
在使用 TypeScript 时,我们经常忽略类型运算符,例如typeof
或 ,keyof
因为它们太初级了。然而,它们在构建类型系统中发挥着重要作用。当正确结合其他 TypeScript 语法时,它们可以帮助您的应用程序开发高级和复杂的类型。让我们尝试一下它们,看看它们能为您带来什么。