阅读 893

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),我将会先解释这些概念,然后分别详细介绍 keyoftypeof,最后会回到 enum 来回答上面的问题。这个答案有点长,但是例子都很容易理解。

字面量类型(literal types)

Typescript 中的字面量类型是更具体的 stringnumber 或 boolean 类型。比如 "Hello World" 是一个 string,但是 string 类型不是 "Hello World""Hello World"string 类型的一个更具体的类型,所以它是一个字面量类型。

一个字面量类型可以被这样定义:

type Greeting = "Hello" 复制代码

这意味着 Greeting 类型的对象只能有一个字符串值 "Hello",并且没有其他 string 类型的值,或者其他任何类型的值,就像是下面代码说的一样:

let greeting: Greeting greeting = "Hello" // OK greeting = "Hi"    // Error: Type '"Hi"' is not assignable to type '"Hello"' 复制代码

字面量类型本身并不是很有用,但是当它和联合类型(union types)、类型别名(type aliases)、类型保护(type guards)组合起来后,它就会变得很强大

下面是联合字面量类型的例子:

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 单独使用

假设现在有一个类型 Tkeyof T 将会给你一个新类型,它是我们前面提到的 联合字面量类型,并且组成它的字面量类型是 T 的属性名称。最后生成的类型是字符串的子类型。

比如来看下下面的 interface

interface Person {     name: string     age: number     location: string } 复制代码

Person 类型上使用 keyof,将会得到一个新类型,如下面代码所示:

type SomeNewType = keyof Person 复制代码

SomeNewType 是一个联合字面量类型("name" | "age" | "location"),它是由 Person 的属性组成的类型。

现在,你可以创建 SomeNewType 类型的对象了:

let newTypeObject: SomeNewType newTypeObject = "name"           // OK newTypeObject = "age"            // OK newTypeObject = "location"       // 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 中,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 '"white" | "black"'


作者:恒十七
链接:https://juejin.cn/post/7023238396931735583


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐