要理解TypeScript中keyof typeof的用法,首先你需要理解什么是文字类型和文字类型的并集。因此,我将首先解释这些概念,然后分别详细解释keyof和typeof。在那之后,我将回到enum来回答问题中所问的问题。这是一个很长的回答,但是例子很容易理解。
文字类型
TypeScript中的文字类型是更具体的字符串、数字或布尔类型。例如,“Hello World”是一个字符串,但字符串不是“Hello World”。"Hello World"是一种更具体的类型字符串,所以它是一个文字类型。
文字类型可以这样声明:
type Greeting = "Hello"
这意味着Greeting类型的对象只能有一个字符串值“Hello”,而没有其他字符串值或任何其他类型的任何其他值,如下所示:
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只
某些类型T的keyof给出了一个新的类型,它是文字类型的联合,这些文字类型是T的属性名称。结果类型是string的子类型。
例如,考虑以下接口:
interface Person {
name: string
age: number
location: string
}
在Person类型上使用keyof操作符会给你一个新的类型,如下所示:
type SomeNewType = keyof Person
这个someenewtype是由类型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类型
在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...