要了解 TypeScript 中 keyof typeof 的用法,首先需要了解什么是文字类型和文字类型的联合。所以,我先解释一下这些概念,然后再详细解释keyof和typeof。之后,我会回到enum 回答问题中的问题。这是一个很长的答案,但例子很容易理解。
文字类型
TypeScript 中的文字类型是更具体的 string、number 或 boolean 类型。例如,"Hello World" 是 string,但 string 不是 "Hello World"。 "Hello World" 是类型 string 的更具体的类型,所以它是一个字面量类型。
文字类型可以声明如下:
type Greeting = "Hello"
这意味着Greeting 类型的对象只能有一个string 值"Hello" 而没有其他string 值或任何其他类型的任何其他值,如以下代码所示:
let greeting: Greeting
greeting = "Hello" // OK
greeting = "Hi" // Error: Type '"Hi"' is not assignable to type '"Hello"'
文字类型本身没有用,但是当与联合类型、类型别名和类型保护结合使用时,它们变得强大。
以下是文字类型联合的示例:
type Greeting = "Hello" | "Hi" | "Welcome"
现在Greeting 类型的对象可以具有"Hello"、"Hi" 或"Welcome" 的值。
let greeting: Greeting
greeting = "Hello" // OK
greeting = "Hi" // OK
greeting = "Welcome" // OK
greeting = "GoodEvening" // Error: Type '"GoodEvening"' is not assignable to type 'Greeting'
仅限keyof
keyof of some type T 为您提供了一个新类型,它是 文字类型的联合,这些文字类型是 T 的属性名称。结果类型是字符串的子类型。
例如,考虑以下interface:
interface Person {
name: string
age: number
location: string
}
在Person 类型上使用keyof 运算符将为您提供一个新类型,如以下代码所示:
type SomeNewType = keyof Person
这个SomeNewType 是由Person 类型的属性组成的文字类型("name" | "age" | "location") 的联合。
现在您可以创建SomeNewType 类型的对象:
let newTypeObject: SomeNewType
newTypeObject = "name" // OK
newTypeObject = "age" // OK
newTypeObject = "location" // OK
newTypeObject = "anyOtherValue" // Error...
keyof typeof 一起在一个对象上
您可能已经知道,typeof 运算符为您提供对象的类型。
在上面的Person 接口示例中,我们已经知道类型,所以我们只需要对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...
keyof typeof enum
在 TypeScript 中,枚举在编译时用作类型,以实现常量的类型安全,但它们在运行时被视为对象。这是因为,一旦将 TypeScript 代码编译为 JavaScript,它们就会转换为普通对象。因此,上述对象的解释也适用于此。问题中OP给出的例子是:
enum ColorsEnum {
white = '#ffffff',
black = '#000000',
}
这里ColorsEnum 在运行时作为对象存在,而不是作为类型存在。所以,我们需要一起调用keyof typeof操作符,如下代码所示:
type Colors = keyof typeof ColorsEnum
let colorLiteral: Colors
colorLiteral = "white" // OK
colorLiteral = "black" // OK
colorLiteral = "red" // Error...
就是这样!希望对您有所帮助。