一、泛型语法的基本使用
1.1 认识泛型
泛型是什么?有什么作用?当我们定义一个变量不确定类型的时候有两种解决方式:
- 使用any:使用any定义时存在的问题:虽然 以 知道传入值的类型但是无法获取函数返回值的类型;另外也失去了ts类型保护的优势
- 使用泛型:泛型指的是在定义函数/接口/类型时,不预先指定具体的类型,而是在使用的时候在指定类型限制的一种特性。
1.2 泛型实现类型参数化
1.3 泛型的基本补充
1.4 泛型接口、类的使用
二、泛型约束、类型条件和映射类型
2.1 泛型约束(Generic Constraints)
2.2 映射类型(Mapped Types)、映射修饰符(Mapping Modifiers)
有的时候,一个类型需要基于另外一个类型,但是你又不想拷贝一份,这个时候可以考虑使用映射类型。
映射类型建立在索引签名的语法上,使用了 PropertyKeys 联合类型的泛型,其中 PropertyKeys 多是通过 keyof 创建,然后循环遍历键名创建一个类型。
三、内置类型工具
3.1 条件类型(Conditional Types)
3.2 在条件类型中推断(infer)
type CalcFnType = (num1: number, num2: string) => number // type CalcReturnType = ReturnType<CalcFnType>; type MyReturnType<T extends (...arg: any[]) => any> = T extends ( ...arg: any[] ) => infer R ? R : never type CalcReturnType = MyReturnType<CalcFnType> // type CalcParameterType = Parameters<CalcFnType> type MyParameters<T extends (...arg: any[]) => any> = T extends ( ...arg: infer P ) => any ? P : never type CalcParameterType = MyParameters<CalcFnType>
复制
3.3 分发条件类型(Distributive Conditional Types)
四、类型体操
4.1 Partial<Type>
用于构造一个Type下面的所有属性都设置为可选的类型interface Person { name: string age: number height: number } // type newPerson = Partial<Person> type MyPartial<T> = { [K in keyof T]?: T[K] } type newPerson = MyPartial<Person>
复制
4.2 Required<Type>
用于构造一个Type下面的所有属性全都设置为必填的类型,这个工具类型跟 Partial 相反。
interface Person { name: string age?: number height?: number } // type newPerson = Required<Person> type MyRequired<T> = { [K in keyof T]-?: T[K] } type newPerson = MyRequired<Person> export {}
复制
4.3 Readonly<Type>
用于构造一个Type下面的所有属性全都设置为只读的类型,意味着这个类型的所有的属性全都不可以重新赋值。
interface Person { name: string age?: number height?: number } // type newPerson = Readonly<Person> type MyReadonly<T> = { readonly [K in keyof T]: T[K] } type newPerson = MyReadonly<Person>
复制
4.4 Record<Keys, Type>
用于构造一个对象类型,它所有的key(键)都是Keys类型,它所有的value(值)都是Type类型。interface Person { name: string age?: number height?: number } type CityType = "上海" | "洛杉矶" // type newRecordType = Record<CityType, Person> type MyRecord<K extends keyof any, T> = { [P in K]: T } type newRecordType = MyRecord<CityType, Person> // type newRecordType = { // 上海: Person; // 洛杉矶: Person; // }
复制
4.5 Pick<Type, Keys>
用于构造一个类型,它是从Type类型里面挑了一些属性Keys。
interface Person { name: string age?: number height?: number } // type newPickType = Pick<Person, "name"> type MyPick<T, K extends keyof T> = { [P in K]: T[P] } type newPickType = MyPick<Person, "name" | "age">
复制
4.6 Omit<Type, Keys>
用于构造一个类型,它是从Type类型里面过滤了一些属性Keys。
interface Person { name: string age?: number height?: number } // type newOmitType = Omit<Person, "name"> type MyOmit<T, K extends keyof T> = { [P in keyof T as P extends K ? never : P]: T[P] } type newOmitType = MyOmit<Person, "name" | "age">
复制
4.7 Exclude<UnionType, ExcludedMembers>
用于构造一个类型,它是从UnionType联合类型里面排除了所有可以赋给ExcludedMembers的类型。
type PropertyTypes = "name" | "age" | "height" // type newType = Exclude<PropertyTypes, "name"> type MyExclude<T, U> = T extends U ? never : T type newType = MyExclude<PropertyTypes, "name">
复制
4.8 Extract<Type, Union>
用于构造一个类型,它是从Type类型里面提取了所有可以赋给Union的类型。
type PropertyTypes = "name" | "age" | "height" // type newType = Extract<PropertyTypes, "name"> type MyExtract<T, U> = T extends U ? T : never type newType = MyExtract<PropertyTypes, "name">
复制
4.9 NonNullable<Type>
用于构造一个类型,这个类型从Type中排除了所有的null、undefined的类型。
type PropertyTypes = "name" | "age" | "height" | null | undefined // type newType = NonNullable<PropertyTypes> type MyNonNullable<T> = T extends null | undefined ? never : T type newType = MyNonNullable<PropertyTypes>
复制
4.10 ReturnType<Type>
用于构造一个含有Type函数的返回值的类型。
type CalcFnType = (num1: number, num2: string) => number // type CalcReturnType = ReturnType<CalcFnType>; type MyReturnType<T extends (...arg: any[]) => any> = T extends ( ...arg: any[] ) => infer R ? R : never type CalcReturnType = MyReturnType<CalcFnType>
复制
4.11 InstanceType<Type>
用于构造一个由所有Type的构造函数的实例类型组成的类型。
// https://stackoverflow.com/questions/70364964/difference-in-typescript-between-types-instancetypetypeof-myclass-and-myc /** * 在TypeScript中, 当你创建出来一个类型的事实上你做了两件事情, 比如Person * 1.创建一个类class Person * 2.创建了两个类型 * 哪两个类型呢? * 1.Person * 2.typeof Person: 构造函数 */ type HYInstanceType<T extends new (...args: any[]) => any> = T extends new ( ...args: any[] ) => infer R ? R : never class Person { name: string age: number constructor(name: string, age: number) { this.name = name this.age = age } } type T = typeof Person type PersonType = InstanceType<typeof Person> // 对于普通的定义来说似乎是没有区别的 const info: Person = { name: "why", age: 18 } const into2: PersonType = { name: "kobe", age: 30 } // 但是如果我们想要做一个工厂函数, 用于帮助我们创建某种类型的对象 // 这里的返回值不可以写T, 因为T的类型会是typeof Person // 这里就可以使用InstanceType<T>, 它可以帮助我们返回构造函数的返回值类型(构造函数创建出来的对象类型) function factory<T extends new (...args: any[]) => any>( ctor: T ): HYInstanceType<T> { return new ctor() } const p1 = factory(Person)
复制