一、泛型语法的基本使用
1. 认识泛型
- 我们可以通过函数来封装一些API,通过传入不同的函数参数,让函数帮助我们完成不同的内容
- 类型参数化:封装一个函数,传入一个参数,并且返回这个参数
2. 泛型实现类型参数化
function foo<Type>(arg: Type): Type {
return arg
}
foo<string>("abc")
foo<number>(123)
- 调用方式二:通过类型推导,自动推导出传入的变量的类型
foo("abc")
foo(123)
3. 泛型的基本补充
function foo<T, E>(a1: T, a2: E) {
}
- 常用名称
- T:Type的缩写,类型
- K、V: key和value的缩写,键值对
- E:Element的缩写,元素
二、泛型接口、类的使用
1. 泛型接口
interface IFoo<T> {
initialValue: T,
valueList: T[],
handleValue: (value: T) => void
}
const foo: IFoo<number> = {
initialValue: 0,
valueList: [0, 1, 3],
handleValue: function(value: number) {
console.log(value)
}
}
2. 泛型类
class Point<T> {
x: T
y: T
constructor(x: T, y: T) {
this.x = x
this.y = y
}
}
const p1 = new Point(10, 20)
const p2 = new Point<number>(10, 20)
const p3: Point<number> = new Point(10, 20)
三、泛型约束和类型条件
1. 泛型约束
- 传入的类型必须有这个属性,也可以有其他属性,但是必须有这个成员
interface ILength {
length: number
}
function getLength<T extends ILength>(args: T) {
return args.length
}
2. 在泛型约束中使用类型参数
- 可以声明一个类型参数,这个类型参数被其他类型参数约束
function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key]
}
const info = {
name: "why",
age: 18
}
console.log(getProperty(info, "name")
四、TypeScript映射类型
1. 映射类型
- 有时候,一个类型需要基于另外一个类型,但是又不想拷贝一份,这个时候可以考虑使用映射类型
- 映射类型建立在索引签名的语法上
- 映射类型,就是使用了PropertyKeys联合类型的泛型;其中PropertyKeys多是通过keyof创建,然后循环遍历键名创建一个类型
interface IPerson {
name: string
age: number
}
type MapType<Type> = {
[property in keyof Type]: boolean
}
type NewPerson = MapType<IPerson>
2. 映射修饰符
- readonly:用于设置属性只读
- ?:用于设置属性可选
type MapType<Type> = {
[property in keyof Type -? Type[property]
}
interface IPerson {
name: string
age: number
height: number
}
type NewPerson = MapType<IPerson>
五、TypeScript条件类型
1. 条件类型
function sum<T extends number | string>(arg1: T, arg2: T): T extends string ? string : number
function sum(arg1: any, arg2: any) {
return arg1 + arg2
}
const res1 = sum(10, 20)
const res2 = sum("aaa", "bbb")
2. 条件类型的类型推断
- infer关键词,可以从正在比较的类型中推荐类型,然后在true分支里引用该推断结果
type CalcFnType = (num1: number, num2: number) => number
type HYReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R: never
type CalcReturnType = HYReturnType<CalcFnType>
type HYParameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any? P: never
type CalcParameterType = HYParameters<CalcFnType>
3. 分支条件类型
- 当在泛型中使用条件类型的时候,如果传入一个联合类型,就会变成分发的
type toArray<Type> = Type extends any ? Type[]: never
type newType = toArray<number | string>
六、类型工具和类型体操
1. Partial
Partial<Type>
- 用于构建一个Type下面的所有属性都设置为可选的类型
interface IWhy {
name: string,
age: number,
slogan?: string
}
type HYPartial<T> = {
[P in keyof T]?: T[P]
}
type IWhyOptional = HYPartial<IWhy>
2. Required
Required<Type>
- 用于构造一个Type下面的所有属性全都设置为必填的类型,这个工具类型与Partial相反
interface IWhy {
name: string,
age: number,
slogan?: string
}
type HYRequired<T> = {
[P in keyof T]-?: T[P]
}
type IWhyRequired = HYRequired<IWhy>
3. Readonly
Readonly<Type>
- 用于构造一个Type下面的所有属性全都设置为只读的类型,意味着这个类型的所有属性全都不可以重新赋值
interface IWhy {
name: string,
age: number,
slogan?: string
}
type HYReadonly<T> = {
readonly [P in keyof T]?: T[P]
}
type IWhyReadonly = Readonly<IWhy>
4. Record
Record<Keys, Type>
- 用于构造一个对象类型,它所有的key(键)都是Keys类型,它所有的value(值)都是Type类型
interface IWhy {
name: string,
age: number,
slogan?: string
}
type keys = keyof IWhy
type Res = keyof any
type HYRecord<Keys extends keyof any, T> = {
[P in Keys]: T
}
type t1 = "上海" | "北京" | "广东"
type IWhy2 = Record<t1, IWhy>
5. Pick
Pick<Type, Keys>
- 用于构造一个类型,它是从Type类型里面挑了一些属性Keys
interface IWhy {
name: string,
age: number,
slogan?: string
}
type HYPick<T, K extends keyof T> = {
[P in K]: T[P]
}
type IWhy2 = HYPick<IWhy, "slogan"|"name">
6. Omit
Omit<Type, Keys>
- 用于构造一个类型,它是从Type类型里面过滤了一些属性Keys
interface IWhy {
name: string,
age: number,
slogan?: string
}
type HYOmit<T, K extends keyof T> = {
[P in keyof T as P extends K ? never: P]: T[P]
}
type IWhy2 = HYOmit<IWhy, "slogan"|"name">
7. Exclude
Exclude<UnionType, ExcludedMembers>
- 用于构造一个类型,它是从UnionType联合类型里面排除了所有可以赋给ExcludedMembers的类型
type IWhy = "sing" | "dance" | "rap"
type HYExclude<T, E> = T extends E? never: T
type IWhy2 = HYExclude<IWhy, "sing"|"rap">
8. Extract
Extract<Type, Union>
- 用于构造一个类型,它是从Type类型里面提取了所有可以赋给Union的类型
type IWhy = "sing" | "dance" | "rap"
type HYExtract<T, E> = T extends E? T: never
type IWhy2 = HYExtract<IWhy, "sing"|"rap">
9. NonNullable
NonNullable<Type>
- 用于构造一个类型,这个类型从Type中排除了所有的null、undefined的类型
type IWhy = "sing" | "dance" | "rap" | null | undefined
type HYNonNullable<T> = T extends null|undefined? never: T
type IWhy2 = HYNonNullable<IWhy>
10. InstanceType
InstanceType<Type>
- 用于构造一个由所有Type的构造类型的实例类型组成的类型
class Person {}
const p1: Person = new Person()
type HYPerson = InstanceType<typeof Person>
const p2: HYPerson = new Person()