TypeScript学习笔记(一):内置工具类型

220 阅读4分钟

TS提供了一系列常用的工具类型来满足日常开发需要。这些类型可以全局访问。

预置知识

在学习类型编程之前,你需要掌握这些知识:

keyof

获取类型的keys列表;

如果传入原始类型,则会自动将原始类型转成引用类型,返回其原型的属性的列表

typeof

获取传入变量的类型

区别于javascript:

  1. 在对原始类型调用时,基本于javascript表现一致,返回小写的原始类型值
  2. 在对引用类型调用时,会推断该引用类型的类型,并返回;而javascript只会返回'object'

in

x in y 可以用于判断y是否包含x;

[k in keyof T]这里也用来遍历类型T的Keys

infer

推断类型

泛型缩写

  • T (Type), 任意类型
  • K (Key), 一般指集合的属性
  • P (Prop), 一般指集合的属性
  • U (UnionType), 一般指联合类型
  • R (ReturnType), 一般指函数返回值类型
  • E (Element),一般指元素类型

Partial<T>

将传入类型的所有属性变为可选。返回传入的类型的所有子集。源码

源码实现

type Partial<T> = {
    [K in keyof T]?: T[K]
}

使用示例

可用于更新数据的场景

interface IUser {
    name: string
    age: number,
    gender: string
}

const user: IUser = {
    name: 'hquestion',
    age: 30,
    gender: 'man'
}

const updateUser = (userPartial: Partial<IUser>) => {
    return {...user, ...userPartial}
}

updateUser({name: 'Gigi'})

Readonly<T>

将传入的类型的所有属性变为只读。源码

源码实现

type Readonly<T> = {
    readonly [K in keyof T]: T[K]
}

使用示例

IUser interface 参考上文

const user: Readonly<Partial<IUser>> = {
    name: 'Jack'
}

// Error: TS2540: Cannot assign to 'name' because it is a read-only property
user.name = 'Jhon'; 

Record<K, T>

创建一个属性类型为K,值类型为T的类型集合。可以用于将一个类型映射到另一个类型。源码

源码实现

type Record<K extends keyof any, T> = {
    [P in K]: T
}

使用示例

type studentNames = | 'Jack' | 'Jhon' | 'Jason';
const studentInfoMap: Record<studentNames, Partial<IUser>> = {
    Jack: {name: 'Jack'},
    Jhon: {name: 'Jhon'},
    Jason: {name: 'Jason'},
};

// Error:  TS2551: Property 'Jacky' does not exist on type 'Record  >'. Did you mean 'Jack'?
studentInfoMap.Jacky = {name: 'Jacky'}

Pick<T, K>

从名称很容易了解到,这个工具类型是从集合中选取一些属性组成一个新的集合类型。即返回类型T的子集。源码

Partial也是返回类型的子集。区别与Partial,Pick可以通过传入指定的Keys,来生成包含特定属性的子集。

源码

type Pick<T, K extends keyof T> = {
    [P in K]: T[P]
}

使用示例

// 假设IMan接口只需要name和age属性
type IMan = Pick<IUser, | 'name' | 'age'>;
const man: IMan = {name: 'Someman', age: 10}
 // Error: TS2339: Property 'gender' does not exist on type 'Pick '.
man.gender = 'male';

type IWoman = Partial<IUser>;
const woman: IWoman = {name: 'Somewoman', age: 20};
woman.gender = 'female'; // Success

Exclude<T, U>

从类型T中剔除部分类型。

因为Omit<T, K>里使用了Exclude, 所以提前介绍Exclude

源码

type Exclude<T, U> = T extends U ? never : T

使用示例

type BC = Exclude<'a' | 'b' | 'c', 'a'>;
// Error: TS2322: Type '"a"' is not assignable to type '"b" | "c"'.
const val: BC = 'a';
// Success
const val: BC = 'b';

Omit<T, K>

从类型T中移除部分属性。

源码

type Omit<T, K> = {
    [P in Exclude<keyof T, K>]: T[P]
}

使用示例

type ISubUser = Omit<IUser, 'age' | 'gender'>
// Success
const subUser: ISubUser = {name: 'subUser'}

// Error: TS2339: Property 'age' does not exist on type 'Pick '.
subUser.age = 20;

Extract<T, U>

提取。提取同时属于T和U的子集类型,即取两者的交集。

与Exclude<T, U>正好相反

源码

type Extract<T, U> = T extends U ? T : never;

使用示例

type A = 'a' | 'b' | 'c'
type B = 'b' | 'd' | 'e'

type AJoinB = Extract<A, B>

// Error: TS2322: Type '"d"' is not assignable to type '"b"'.
const val: AJoinB = 'd';
// Success
const val: AJoinB = 'b';

NonNullable<T>

从类型T上剔除null和undefined。

源码

type NonNullable<T> = T extends undefined | null ? never : T

使用示例

const user3: NonNullable<IUser> = {
    name: 'xx',
    age: 20,
    // Error
    gender: undefined,
}

Parameters<T>

从函数的参数列表生成一个参数列表类型元组的类型。

源码

type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any? P : never

使用示例

type fnA = (name: string, age: number) => void

// 将得到:type Atype = [string, number]
type AType = Parameters<fnA>;
// Error: TS2322: Type 'string' is not assignable to type 'number'.
const atype: AType = ['name', 'age']

ConstructorParameters<T>

从构造函数的参数列表生成参数列表元组类型,使用上与Parameters<T>类似,不再赘述。

源码

type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any? P : never

ReturnType<T>

从函数的返回值类型生成一个新的类型。

源码

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any

使用示例

type fn = () => string

// 从这个简单的例子,我们一眼可以知道下面类型即:type FnReturn = string
type FnReturn = ReturnType<fn>

const fnReturnVal: FnReturn = '1'; 

InstanceType<T>

生成构造函数返回值类型的类型。如果传入的不是一个构造函数,即返回any

源码

type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any

Required<T>

与Partial相反,将T类型的所有属性都设置为必填。

源码

type Required<T> = {
    [K in keyof T]-: T[K]
}

使用示例

// Partial 生成一个可选的类型
type IOptionalUser = Partial<IUser>
// 再通过Required转化为必选类型
type IRequiredUser = Required<IOptionalUser>

const user: IRequiredUser = {
    name: 'Jack',
    age: 20,
    gender: 'male'
}

其他内置工具

  • ThisParameterType<T>
  • OmitThisParameterType<T>
  • ThisType<T>

额外的非内置类型定义

DeepReadonly<T>

DeepReadonly用来深度遍历 T,并将其所有属性变成只读类型

type DeepReadonly<T> = { readonly [P in keyof T]: DeepReadonly<T[P]> }

ValueOf<T>

ValueOf与keyof相对应。取出指定类型的所有 value

type ValueOf<T> = T[keyof T]

Mutable<T>

用来将所有属性的readonly移除:

type Mutable<T> = {
    -readonly [K in keyof T]: T[K]
}

相关文章