泛型是什么
泛型允许我们在强类型语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型在ts中,定义函数,接口或者类的时候,不预先定义好具体的类型,而是在使用时候才指定类型的一种特性。
function returnItem(param:number):number{
return param
}
function returnItem(param:string):string{
return param
}
有两个函数,一个返回number,一个返回string,这种方式代码重复度高,需要些两遍,虽然可以使用any类型去替代,但这在项目中基本是不允许的,这时候加上泛型
function returnItem<T>(param:T):T{
return param
}
泛型创造灵活,可复用代码
使用方式
泛型通过<>
的形式进行表述,声明:
- 函数
- 接口
- 类
函数声明
function returnItem<T>(param:T):T{
return param
}
//定义泛型的时候,可以一次性定义多个类型参数,比如同时定义泛型T和U:
function swap<T,U>(tuple:[T,U]:[U,T]){
return [tuple[1],tuple[0]];
}
swap([7,'seven']);//['seven',7]
接口声明
interface ReturnItemFn<T>{
(param:T):T
}
const returnItem:ReturnItemFn<number> = param => param
类声明
使用泛型声明类的时候,可以作用于类本身,也可以作用于类的成员函数
class Stack<T>{
private arr:T[] = []
public push(item:T){
this.arr.push(item);
}
public pop(){
this.arr.pop()
}
}
const stack = new Stack<number>();
如果上面只能传递string和number类型,这时候就可以使用<T extends xx>
的方式实现约束泛型
type Params = string | number
class Stack<T extends Params>{
private arr:T[] = []
public push(item:T){
this.arr.push(item)
}
public pop(){
this.arr.pop()
}
}
const stack = new Stack<boolean>() //类型“boolean”不满足约束“Params”
除了上述的形式,泛型更高级的使用如下:
例如要设计一个函数,这个函数接受两个参数,一个参数为对象,另一个参数为对象上的属性,我们通过这两个参数返回这个属性的值
这时候就设计到泛型的索引类型和约束类型共同实现
索引类型、约束类型
索引类型 keyof T
把传入的对象的属性类型取出生成一个联合类型,这里的泛型U被约束在这个联合类型中
function getValue<T extends object, U extends keyof T>(obj:T,key:U){
return obj[key]
}
多类型约束
例如需要实现两个接口的类型约束:
interface FirstInterface {
doSomething():number
}
interface SecondInterface {
doSomethingElse():string
}
可以创建一个接口继承上述两个接口
interface ChildInterface extends FirstInterface,SecondInterface {
}
class Demo<T extends ChildInterface>{
private genericProperty:T
constructor(genericProperty:T){
this.genericProperty = genericProperty
}
useT(){
this.genericProperty.doSomething()
this.genericProperty.doSomethingElse()
}
}