知识专栏 | 专栏链接 |
---|---|
TypeScript知识专栏 | https://blog.csdn.net/xsl_hr/category_12030346.html?spm=1001.2014.3001.5482 |
有关TypeScript的相关知识可以前往TypeScript知识专栏查看复习!!
最近在前端的深入学习过程中,接触了与网络请求相关的内容,于是计划用三个专栏(HTTP、Axios、Ajax)和零碎文章总结记录最近的学习笔记。由于项目前端技术栈的脚本语言为TypeScript
,在研读小程序异步请求封装部分的代码时,碰到了几个关于TypeScript
的小知识点不太清楚。
因此,本文以 TypeScript中的typeof()
、keyof()
为主要内容展开讲解。
在使用TypeScript的时候,我们经常会类似下面的例子一样编写代码:
// 定义一个枚举类型的对象
enum ColorsEnum {
white = '#ffffff',
black = '#000000',
}
// 定义Colors类型 里面的值只能是ColorsEnum中的值
type Colors = keyof typeof ColorsEnum;
最后一行代码等价于:
type Colors = "white" | "black" // Colors的值只能是“white”和“black”中的一个
那么其中keyof typeof
是如何工作的呢?下面我们开始切入正题,开始详细讲述。
想要理解TypeScript里的keyof typeof
是如何工作的,首先需要理解什么是“字面量类型(literal types)”和“联合字面量类型(union of literal types)”,下面我们来解释一下这两个概念,再来详细介绍keyof
和typeof
,最后回到enum来回答上面的问题。
Typescript 中的字面量类型是更具体的 string
, number
或 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'
假设现在有一个类型 T
(泛型),keyof 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'
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"'
在 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"'
以上就是关于==TypeScript中的typeof()、keyof()==的分享,相信看完这篇文章的小伙伴们一定有了一定的收获。当然,可能有不足的地方,欢迎大家在评论区留言指正!