TypeScript关于keyof和typeof的用法分析
在用 TypeScript 的时候,我们常会类似下面的例子一样写~
enum ColorsEnum {
white="#ffffff",
black="#000000",
}
type Colors = keyof typeof ColorsEnum;
其中最后一行等价于:
type Colors = "white" | "black"
keyof
和 typeof
是如何工作的?
想要理解 TypeScript 中 keyof
和 typeof
是如何工作的,首先需要理解什么是 字面量类型(literal types)
和 联合字面量类型(union of literal types
,我将会先解释这些概念,然后分别详细介绍 keyof
和 typeof
,最后会回到 enum
来回答上面的问题。
字面量类型(literal types)
TypeScript 中的字面量类型是更具体的 string
, number
或 boolean
类型。比如 "张三"
是一个 string
,但是 string
类型不是 "张三"
,"张三"
是 string
类型的一个更具体的类型,所以它是一个字面量类型。
一个字面量类型可以被这样定义:
type NameType = "关羽"
这意味着 Name
类型的对象只能有一个字符串值 张三
,并且没有其他 string
类型的值,或者其他任何类型的值,就像下面代码说的一样:
let name: NameType
name = "关羽" // OK
name = "张飞" // Error: Type '"关羽"' is not assignable to type '"关羽"'
字面量类型本身并不是很有用,但是当它和联合类型(union types)、类型别名(type aliases)、类型保护(type guards)组合起来后,它就变得很强大。
下面是联合字面量类型的例子:
type NameType = "马超" | "赵云" | "黄忠"
现在 NameType
类型对象的值可以是 "马超"
, "赵云"
或者 "黄忠"
。
let name: NameType
name = "马超" // OK
name = "赵云" // OK
name = "黄忠" // OK
name = "刘备" // Error: Type '"刘备"' is not assignable to type '"NameType"'
keyof 单独使用
假设现在有一个类型 T
, keyof T
将会给你一个新的类型,她是我们前面提到的 联合字面量类型
,并且组成他的字面量类型是 T
的属性名称。最后生成的类型是字符串的子类型。
比如下面的 interface
:
interface Person {
name: string
age: number
address: string
}
在 Person
类型上使用 keyof
,将会得到一个新的类型,如下:
type SomeNewType = keyof Person
SomeNewType
是一个联合字面量类型("name" | "age" | address
),它是由 Person
的属性组成的类型。
现在,你可以创建 SomeNewType
类型的对象了:
let newTypeObject: SomeNewType
newTypeObject = "name" // OK
newTypeObject = "age" // OK
newTypeObject = "address" // OK
newTypeObject = "anyOtherValue" // Error...Type '"anyOtherValue"' is not assignable to type 'keyof Person'
keyof typeof 同时使用
你可能已经知道,typeof
运算符为你提供对象的类型,上面例子中 Person
interface,我们已经知道它的类型,所以我们只需要在 Person
上使用 keyof
操作符。
但是,当我们不知道对象的类型,或者我们只有一个值,类似于下面的情况,应该怎么办呢?
const bmw = { name: "BMW", power: "1000hp" }
这就是我们需要一起使用 keyof typeof
的地方。
typeof bmw
给到你他们的类型 { name: string, power: string }
接着 keyof
操作符给到你联合字面量类型,像下面代码描述的一样:
type CarLiteralType = keyof typeof bmw
let carPropertyLiteral: CarLiteralType
carPropertyLiteral = "name" // OK
carPropertyLiteral = "power" // OK
carPropertyLiteral = "anyOther" // Error...Type '"anyOther"' is not assignable to type '"name" | "power"'
在 enum 上使用 keyof typeof
在 Typescript 中,enmu
在编译时被用作类型,用来实现常量的类型安全,但是它们在运行时被视为对象。这是因为,当 TypeScript 代码被编译为 JavaScript 时,它们会被转化为普通对象。接着我们回顾一下,最后开始我们提出问题的例子是这样的:
enum ColorsEnum {
white = '#ffffff',
black = '#000000',
}
这里 ColorEnum
在运行时作为一个对象存在,不是一个类型,所以,我们需要一起使用 keyof typeof
这两个操作符,如下代码所示:
type Colors = keyof typeof ColorsEnum
let colorLiteral: Colors
colorLiteral = "#ffffff" // OK
colorLiteral = "#000000" // OK
colorLiteral = "#00ffff" // Error...Type '"#00ffff"' is not assignable to type '"#ffffff" | "#000000"'
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?