简介
泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
作用
可以保证类型安全的前提下,让函数、接口或类与多种类型一起工作,从而实现复用
基本使用
举个例子:
创建一个id函数、该函数传入什么数据就返回数据本身,也就是参数和返回值类型相同。
function id(value:number): number {return value
}id<number>(99) // 99
function id(value:string): string {return value
}id<string>('hhh') // hhh
综上所述、上面两个函数接收的类型是写死的,只能传入相应的数据类型,为了能让函数接口任意类型吗,可以将参数类型改为any
。但是这样就失去TS的类型保护,类型不安全。
这时候,泛型
就能派上用场了。
function id<T>(value:T):T {return value
}id<number>(99) // 99
id<string>('hhh') // hhh
id<number[]>([1,2,3]) // [1,2,3]
- 在函数名称的后面添加
<>
,其中尖括号里面的T
就是类型参数,它用来处理类型
而不是值,它可以是任意合法的变量名称 - 因为
T
是类型,因此可以将T
作为参数和返回值的类型,表示参数和返回值具有相同的类型 - 由于TS内部会采用一种叫做
类型参数推断
的机制,来根据传入的数据推断出相对应的类型,针对一些基础数据类型,可以省略不写。比如上述id<number>(99)
可直接写成id(99)
、id<string>('hhh')
可简单写成id('hhh')
。当编译器无法推断类型或者推断的类型不准确时,就需要显式的传入类型参数。比如id<number[]>([1,2,3])
。
单个类型参数 VS 多个类型参数
单个类型参数
function id<T>(value:T):T {return value
}
id<number>(99) // 99
顾名思义:类型参数只有一个,如上,只有一个 T
多个类型参数
function swap<T, U>(value: [T, U]): [U, T] {return [value[1], value[0]];
}swap([18, 'age']); // ['age', 18]
多个类型参数之间可进行相互约束
多类型变量之间还可以进行约束,比如第二个类型变量所第一个类型变量约束。
function getPro<T, K extends keyof T> (obj:T, key:K) {return obj[[key]
}getPro({name:'abc',age:18},'age')
getPro('abc','length')
getPro([a,b,c],'length')
- keyof 接收一个对象类型,生成其键名称或数字的联合类型
- 类型K受类型T的约束,上述可以理解为K只能是T中所存在的键中任意一个,或者说只能访问对象中存在的属性。
泛型约束
在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以导致无法访问它的属性和方法。如下:
function id<T>(value:T):T {console.log(value.length) //这段代码编译器会报错:Property 'length' does not exist on type 'T'. return value
}
上述代码中无法保证传入的数据一定存在length属性。所以,就需要为泛型添加约束。(只允许这个函数传入那些包含 length
属性的变量)
指定更加具体的类型
function id<T>(value:T[]):T[] {console.log(value.length) return value
}
如上、可将T
改成T[]
,也就是T类型的数组,这样数组就一定存在lengh属性,就可以正常访问了。
使用 extends 添加约束
interface TLength {length:number
}function id<T extends TLength>(value:T): T {console.log(value.length) return value
}id(['xxx','yyy'])
id('hhhhh')
id({length:10,name:'abcd'})
- 创建描述约束的接口TLength,该接口提供length属性
- 通过
extends
关键字使用该接口,为泛型添加约束。
泛型接口
接口也可以配合泛型使用
泛型类
泛型工具类型
Partial<Type>
用来创建一个类型,将Type中的所有属性都设置为可选
Readonly<Type>
用来创建一个类型,将Type中的所有属性都设置为只读
Pick<Type,Keys>
从Type中选择一组属性来构造新类型
Record<Keys,Type>
构造一个对象类型,属性键为Keys,属性类型为Type