字面量类型
在了解typeof和keyof之前,我们首先需要了解什么是字面量类型以及联合字面量类型。
TypeScript 中的字面量类型是更具体的string、number或boolean类型,它可以被这样定义:
type Greeting = 'hello';
这意味着类型为Greeting的变量只能有一个字符串值’hello’:
const foo: Greeting = 'hello';
const bar: Greeting = 'world'; // Type '"world"' is not assignable to type '"hello"'.ts(2322)
字面量类型本身可能并不是很实用,但是它可以和联合类型一起组合出强大的抽象,也就是我们说的联合字面量类型:
type Greeting = 'hello' | 'world';
const foo: Greeting = 'hello';
const bar: Greeting = 'world';
typeof
如果对象是一个嵌套的对象,typeof也能够正确获取到它们的类型。
const p = {
name: 'CJ',
age: 18,
address: {
city: 'SH'
}
};
//typeof p就会得到
{
name: string;
age: number;
address: {
city: string;
};
};
//那么
type Person = typeof p;
// 相当于
type Person = {
name: string;
age: number;
address: {
city: string;
};
};
keyof
一个最基本的keyof用法如下,我们通过keyof Person得到一个PersonKeys类型,它是一个联合字面量类型,包含了Person所有的属性。所以我们在对类型为PersonKeys的变量赋值时,只能赋值为’name’或者’age’。
type Person = {
name: string;
age: number;
};
type PersonKeys = keyof Person;
const key1: PersonKeys = 'name';
const key2: PersonKeys = 'age';
// Type '"addr"' is not assignable to type 'keyof Person'.
const key3: PersonKeys = 'addr';
typeof和keyof一起使用
你可能已经知道,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 assign
typeof和keyof和枚举一起使用
在 Typescript 中,enum 在编译时被用作类型,用来实现常量的类型安全,但是它们在运行时被视为对象。这是因为,当 Typescript 代码被编译为 Javascript 时,它们会被转换为普通对象。接着我们回顾一下,最开始我们提出问题的例子是这样的:
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...Type '"red"' is not assignable to type '"whi