一、泛型语法的基本使用
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)