「这是我参与2022首次更文挑战的第24天,活动详情查看:2022首次更文挑战」。
JavaScript 中有很多内置对象,它们可以直接在 TypeScript 中当做定义好了的类型。
内置对象是指根据标准在全局作用域 global
上存在的对象,这里的标准指的是 ECMAcript
和其他环境(比如DOM)的标准。
内置类型
ECMAScript 的内置对象
比如,Array
、Date
、Error
等,
const nums: Array<number> = [1,2,3]
const date: Date = new Date()
const err: Error = new Error('Error!');
const reg: RegExp = /abc/;
Math.pow(2, 9)
以 Array
为例,按住 comand/ctrl
,再鼠标左键点击一下,就能跳转到类型声明的地方。
可以看到,Array 这个类型是用 interface 定义的,有多个不同版本的 .d.ts
文件声明了这个类型。
在 TS 中,重复声明一个 interface,会把所有的声明全部合并,这里所有的 .d.ts
文件合并出来的 Array 接口,就组合成了 Array 内置类型的全部属性和功能。
DOM 和 BOM
比如 HTMLElement
、NodeList
、MouseEvent
等
let body: HTMLElement = document.body
let allDiv: NodeList = document.querySelectorAll('div');
document.addEventListener('click', (e: MouseEvent) => {
e.preventDefault()
// Do something
});
工具类型(Utility Types)
为了方便开发者使用, TypeScript 内置了一些常用的工具类型,比如 typeof
、extends
、keyof
等,这里介绍几个,起一个抛砖引玉的作用,更多可参考 Ts高手篇:22个示例深入讲解Ts最晦涩难懂的高级类型工具
毕竟工具函数遇到了去查就行,死记硬背就太枯燥了,熟能生巧。
typeof
typeof
操作符可以用来获取一个变量声明的类型。
之前介绍 类型保护
的时候,就已经讲过 typeof 操作符了,我们来复习一下,
function getLength(arg: number | string): number {
if(typeof arg === 'string') {
return arg.length
} else {
return arg.toString().length
}
}
extends
extends 用于 约束泛型
,之前讲过,复习一下,
interface ILength {
length: number
}
function printLength<T extends ILength>(arg: T): T {
console.log(arg.length)
return arg
}
这样入参就一定要有 length 属性,比如 str、arr、obj 都可以, num 就不行。
const str = printLength('lin')
const arr = printLength([1,2,3])
const obj = printLength({ length: 10 })
const num = printLength(10) // 报错,Argument of type 'number' is not assignable to parameter of type 'ILength'
keyof
keyof
操作符可以用于获取某种类型的所有键,其返回类型是联合类型。
interface IPerson {
name: string;
age: number;
}
type Test = keyof IPerson; // 'name' | 'age'
上面的例子,Test 类型变成了一个字符串字面量。
之前介绍 泛型约束后端入参
的时候,介绍过 keyof
,复习一下,
interface API {
'/book/detail': {
id: number,
},
'/book/comment': {
id: number
comment: string
}
...
}
function request<T extends keyof API>(url: T, obj: API[T]) {
return axios.post(url, obj)
}
in
in
用来实现遍历
type Person = "name" | "school" | "major"
type Obj = {
[p in Person]: string
}
Partial
Partial<T>
将T
的所有属性变成可选的,例如:
interface IPerson {
name: string
age: number
}
let p1: IPerson = {
name: 'lin',
age: 18
}
使用了 IPerson 接口,就一定要传 name 和 age 属性,
使用 Partial
改造一下,就可以变成可选属性,
interface IPerson {
name: string
age: number
}
type IPartial = Partial<IPerson>
let p1: IPartial = {}
Partial原理分析
Partial
的实现用到了上文提到的 in
和 keyof
type Partial<T> = {
[P in keyof T]?: T[P];
}
[P in keyof T]
遍历T
上的所有属性?:
设置为属性为可选的T[P]
设置类型为原来的类型 看似高大上的东西其实这么简单,其他的一些工具类型(比如 Pick、Record、Exclude 等)其实也很简单,只要去分析过,就会发现泛型的写法和 JS 的语法非常类似,只是把传参的变量
换成了类型
而已。
Omit
Omit<T, U>
从类型 T
中剔除 U
中的所有属性。
interface IPerson {
name: string
age: number
}
type IOmit = Omit<IPerson, 'age'>
这样就剔除了 IPerson 上的 age 属性。
小结
本文提到的这些内置类型,全都定义在TypeScript 核心库的定义文件,这些文件包含了es2015 到 es2022 的全部 JS 语法,这里也应证了那句话——TS 是 JS 的超集。
至于工具类型,知道一些常用的,其他的遇到了再去查就行,不必死记硬背,即使忘了某个工具类型是怎么用的,去查一下很快就熟悉了,写多了也会慢慢熟悉的。
往期