TypeScript 映射类型
只读类型 Readonly
定义:用于将 T
类型的所有属性设置为只读状态。
type Readonly<T> = { readonly [P in keyof T]: T[P] }
用法:
interface Person { name: string age: number } const person: Readonly<Person> = { name: 'Lucy', age: 22, } // 会报错:Cannot assign to 'name' because it is a read-only property person.name = 'Lily'
readonly
只读, 被readonly
标记的属性只能在声明时或类的构造函数中赋值,之后将不可改(即只读属性)。
只读数组 ReadonlyArray
定义:用于将 T
类型的数组设置为只读状态。只能在数组初始化时为变量赋值,之后数组无法修改。
interface ReadonlyArray<T> { [Symbol.iterator](): IterableIterator<T> entries(): IterableIterator<[number, T]> keys(): IterableIterator<number> values(): IterableIterator<T> }
用法:
interface Person { name: string } const personList: ReadonlyArray<Person> = [{ name: 'Jack' }, { name: 'Rose' }] // 会报错:Property 'push' does not exist on type 'readonly Person[]' // personList.push({ name: 'Lucy' }) // 但是内部元素如果是引用类型,元素自身是可以进行修改的 personList[0].name = 'Lily'
可选类型 Partial
定义:用于将 T
类型的所有属性设置为可选状态,首先通过 keyof T
,取出类型 T
的所有属性,然后通过 in
操作符进行遍历,最后在属性后加上 ?
,将属性变为可选属性。
type Partial<T> = { [P in keyof T]?: T[P] }
用法:
interface Organization { id: number name: string address: string type: string nationality: string } const params: Partial<Organization> = { address: '...new address', } // 和上面 Partial 效果一样 const params: Pick<Organization, 'address'> = { address: '...new address', }
必选类型 Required
定义:和 Partial<T>
作用相反,用于将 T
类型的所有属性设置为必选状态,首先通过 keyof T
,取出类型 T
的所有属性, 然后通过 in
操作符进行遍历,最后在属性后的 ?
前加上 -
,将属性变为必选属性。
type Required<T> = { [P in keyof T]-?: T[P] }
用法:
interface Person { name?: string age?: number } // 使用 Required 映射后返回的新类型,name 和 age 都变成了必选属性 // 会报错:Type '{}' is missing the following properties from type 'Required<Person>': name, age let person: Required<Person> = {}
提取属性 Pick
定义:从 T
类型中提取部分属性,作为新的返回类型。
type Pick<T, K extends keyof T> = { [P in K]: T[P] }
用法:
interface Goods { type: string goodsName: string price: number } // type RequestGoodsParams = { // goodsName: string; // price: number; // } type RequestGoodsParams = Pick<Goods, 'goodsName' | 'price'> const params: RequestGoodsParams = { goodsName: '', price: 10, }
排除属性 Omit
定义:和 Pick
作用相反,用于从 T
类型中,排除部分属性,然后返回一个新类型。
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
用法:
interface Rectangular { length: number height: number width: number } // type Square = { // length: number; // } type Square = Omit<Rectangular, 'height' | 'width'>
Omit
推导过程:
type Person = { name: string age: string location: string } type PersonWithoutLocation = Omit<Person, 'location'> // 推导 type PersonWithoutLocation = Pick<Person, Exclude<'name' | 'age' | 'location', 'location'>> // 推导 type PersonWithoutLocation = Pick< Person, ('name' extends 'location' ? never : 'name') | ('age' extends 'location' ? never : 'age') | ('location' extends 'location' ? never : 'location') > // 推导 type PersonWithoutLocation = Pick<Person, 'name' | 'age' | never> // 推导 type PersonWithoutLocation = Pick<Person, 'name' | 'age'> // 推导 type PersonWithoutLocation = { [p in 'name' | 'age']: Person[p] } // 推导 type PersonWithoutLocation = { name: string age: string }
摘取类型 Extract<T,U>
定义:提取 T
中可以赋值给 U
的类型。
type Extract<T, U> = T extends U ? T : never
用法:
type T01 = Extract<'a' | 'b' | 'c' | 'd', 'a' | 'c' | 'f'> // 'a' | 'c' type T02 = Extract<string | number | (() => void), Function> // () => void
排除类型 Exclude<T,U>
定义:与 Extract
用法相反,从 T
中剔除可以赋值给 U
的类型。
type Exclude<T, U> = T extends U ? never : T
用法:
type T00 = Exclude<'a' | 'b' | 'c' | 'd', 'a' | 'c' | 'f'> // 'b' | 'd' type T01 = Exclude<string | number | (() => void), Function> // string | number
属性映射 Record<K,T>
定义:接收两个泛型,K
必须可以是可以赋值给 string | number | symbol
的类型,通过 in
操作符对 K
进行遍历,每一个属性的类型都必须是 T
类型。
type Record<K extends string | number | symbol, T> = { [P in K]: T }
Record
是 TypeScript 中一个很实用的范型类型。它需要两个具体的参数类型,Record<K, V>
用于指定一个对象的类型。其中,对象的所有 key 都是 K 类型的,而这些 key 对应的值则都是 V 类型的。如果不使用 Record
类型,可能需要用如下的方法来达到同等的效果:
type RecordExample = Record<string, number> // 等价于 interface EquivalentExample { [key: string]: number }
用法一:将 Person
类型的数组转化成对象映射:
interface Person { name: string age: number } const personList = [ { name: 'Jack', age: 26 }, { name: 'Lucy', age: 22 }, { name: 'Rose', age: 18 }, ] const personMap: Record<string, Person> = {} personList.forEach((person) => { personMap[person.name] = person })
用法二:传递参数时,希望参数是一个对象,但是不确定具体的类型,就可以使用 Record
作为参数类型:
function doSomething(obj: Record<string, any>) {}
用法三:写一个函数,可以将参数对象中所有的值都转化成对应的数字,保证输入和输出的对象有相同的 key:
type Input = Record<string, string> function transform<T extends Input>(input: T): Record<keyof T, number> { const keys: (keyof T)[] = Object.keys(input) return keys.reduce((acc, key) => { acc[key] = +input[key] return acc }, {} as Record<keyof T, number>) }
然而,需要注意的一点是,在使用联合类型的时候 Record
本身也存在局限性(这一点本身是 TypeScript 的局限性)。还是以上面的 'apple' | 'banana' | 'orange'
为例,如果这么写,那么下面的代码将是错误的:
type Fruit = 'apple' | 'banana' | 'orange' type Price = Record<Fruit, number> // type error const prices: Price = { apple: 20, }
Record
天然并不能解决可选 key 的情况。Record<'A' | 'B', number>
的含义是 A 和 B 都需要是这个类型的 key,而不是说只需要有 A 或 B 一个做 key 就可以了。对于这种需要可选的情况,可以再套上一层 Partial
来满足需求:
type Price = Partial<Record<Fruit, number>> // correct const prices: Price = { apple: 20, }
不可为空类型 NonNullable
定义:从 T
中剔除 null
、undefined
、never
类型,不会剔除 void
、unknow
类型。
type NonNullable<T> = T extends null | undefined ? never : T
用法:
type T01 = NonNullable<string | number | undefined> // string | number type T02 = NonNullable<(() => string) | string[] | null | undefined> // (() => string) | string[] type T03 = NonNullable<{ name?: string; age: number } | string[] | null | undefined> // {name?: string, age: number} | string[]
构造函数参数类型 ConstructorParameters
定义:返回 class 中构造函数参数类型组成的元组类型。
type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never
用法:
class Person { name: string age: number gender: 'man' | 'women' constructor(name: string, age: number, gender: 'man' | 'women') { this.name = name this.age = age this.gender = gender } } type ConstructorType = ConstructorParameters<typeof Person> // [name: string, age: number, gender: 'man' | 'women'] const params: ConstructorType = ['Jack', 20, 'man']
实例类型 InstanceType
定义:获取 class
构造函数的返回类型。
type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any
用法:
class Person { name: string age: number gender: 'man' | 'women' constructor(name: string, age: number, gender: 'man' | 'women') { this.name = name this.age = age this.gender = gender } } type Instance = InstanceType<typeof Person> // Person const params: Instance = { name: 'Jack', age: 20, gender: 'man', }
函数参数类型 Parameters
定义:获取函数的参数类型组成的元组类型。
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never
用法:
type FunctionType = (name: string, age: number) => boolean type FunctionParamsType = Parameters<FunctionType> // [name: string, age: number] const params: FunctionParamsType = ['Jack', 20]
函数返回值类型 ReturnType
定义:获取函数的返回值类型。
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
使用:
type FunctionType = (name: string, age: number) => boolean | string type FunctionReturnType = ReturnType<FunctionType> // boolean | string
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 变量声明与解构赋值
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论