泛型:指在定义函数、接口、类时,不预先指定具体的类型,而是在使用的时候在指定类型的一种特性。
一、泛型函数
//需求:封装一个函数,可以创建一个指定长度的数组,同时将每一项都填充一个默认值
//1、使用any类型
function getArr(val:any,len:number):any[]{
const arr:any[] = []
for(let i = 0; i(val:T,len:number): T[]{
const arr:Array = []
for(let i = 0; i手动指定类型,即使不指定类型,ts也会自动推论出数据的类型
const arr3 = getArr2(100.123,3)
const arr4 = getArr2('abc',3)
多个泛型参数的函数:函数中有多个泛型的参数
function getMsg(key:K,value:V){
return [key,value]
}
const arr = getMsg('age',18)
console.log(arr) //['age',18]
二、泛型接口
在定义接口时,为接口中的属性或方法定义泛型类型,在使用接口时,再指定具体的泛型类型。
类的泛型接口
//定义一个泛型接口-类
interface IBaseCRUD{
data: T[] //含有data属性,一个元素类型为T的数组,用来存储数据信息
add:(t:T)=>void //含有添加数据信息的方法
getById: (id: number) => T //含有查找数据信息的方法
}
//定义一个人类信息的类
class Person{
id?:number
name: string
age: number
constructor(name:string,age:number){
this.name = name
this.age = age
}
}
//定义一个满足IBaseCRUD接口可添加查找人类信息的类
class PersonCRUD implements IBaseCRUD{
data: Array = [] //初始化
add(person:Person):void{
//自动生成id
//person.id = Date.now()+Math.random()
person.id = this.data.length//测试
//向data中添加人类信息
this.data.push(person)
}
getById(id:number):Person{
return this.data.find(person=>person.id === id)
}
}
//实例化PersonCRUD
const personCRUD = new PersonCRUD
personCRUD.add(new Person('Liane',18))
personCRUD.add(new Person('Ann',16))
console.log(personCRUD.data)//[Person {name: "Liane", age: 18, id: 0},Person {name: "Ann", age: 16, id: 1}]
console.log(personCRUD.getById(0))//Person {name: "Liane", age: 18, id: 0}
函数的泛型接口
//定义一个函数的泛型接口
interface IGetArr{
(val:T,len:number):Array
}
//定义一个符合IGetArr接口的函数--注:必须注明接口的类型
let getArr:IGetArr = function(val:T,len:number){
let result:T[] = []//默认值为[]
for(let i = 0; i('a',3))//提示错误
console.log(getArr('a',3))//['a','a','a']
console.log(getArr(123,3))//[123,123,123]
三、泛型类
一个类中的属性值的类型不确定,方法中的参数及返回值类型不确定的情况,可以定义泛型类
//定义一个泛型类
class GenericNumber {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
四、泛型约束
在函数内部使用泛型变量的时候,由于事先不知道它是那种类型,所以不能随意操作它的属性和方法。
function loggingIdentity(arg: T): T {
console.log(arg.length);
return arg;
}
// index.ts(2,19): error TS2339: Property 'length' does not exist on type 'T'.
上例中,泛型 T
不一定包含属性 length
,所以编译的时候报错了。
这时,我们可以对泛型进行约束,只允许这个函数传入那些包含 length
属性的变量。这就是泛型约束:
interface Lengthwise {
length: number;
}
function loggingIdentity(arg: T): T {
console.log(arg.length);
return arg;
}
上例中,我们使用了 extends
约束了泛型 T
必须符合接口 Lengthwise
的形状,也就是必须包含 length
属性。
此时如果调用 loggingIdentity
的时候,传入的 arg
不包含 length
,那么在编译阶段就会报错了:
interface Lengthwise {
length: number;
}
function loggingIdentity(arg: T): T {
console.log(arg.length);
return arg;
}
loggingIdentity(7);
// index.ts(10,17): error TS2345: Argument of type '7' is not assignable to parameter of type 'Lengthwise'.
多个类型参数之间也可以互相约束:
function copyFields(target: T, source: U): T {
for (let id in source) {
target[id] = (source)[id];
}
return target;
}
let x = { a: 1, b: 2, c: 3, d: 4 };
copyFields(x, { b: 10, d: 20 });
上例中,我们使用了两个类型参数,其中要求 T
继承 U
,这样就保证了 U
上不会出现 T
中不存在的字段。