TypeScript-泛型

Posted Liane

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TypeScript-泛型相关的知识,希望对你有一定的参考价值。

泛型:指在定义函数、接口、类时,不预先指定具体的类型,而是在使用的时候在指定类型的一种特性。
一、泛型函数

//需求:封装一个函数,可以创建一个指定长度的数组,同时将每一项都填充一个默认值
//1、使用any类型
function getArr(val:any,len:number):any[]{
    const arr:any[] = []
    for(let i = 0; i<len; i++){
        arr.push(val)
    }
    return arr
}
const arr1 = getArr(\'abcde\',3)
const arr2 = getArr(100.123,3)
console.log(arr1) //["abcde", "abcde", "abcde"]
console.log(arr2) //[100.123, 100.123, 100.123]
//使用any类型后,会出现TS静态检查体现不了的缺点,因此可以使用泛型来解决
//2、使用泛型 
function getArr2<T>(val:T,len:number): T[]{
    const arr:Array<T> = []
    for(let i = 0; i<len; i++){
        arr.push(val)
    }
    return arr
}
//在调用函数时,使用<>手动指定类型,即使不指定类型,ts也会自动推论出数据的类型
const arr3 = getArr2<number>(100.123,3)
const arr4 = getArr2<string>(\'abc\',3)

多个泛型参数的函数:函数中有多个泛型的参数

function getMsg<K,V>(key:K,value:V){
    return [key,value]
} 
const arr = getMsg<string,number>(\'age\',18)
console.log(arr) //[\'age\',18]

二、泛型接口
在定义接口时,为接口中的属性或方法定义泛型类型,在使用接口时,再指定具体的泛型类型。
类的泛型接口

//定义一个泛型接口-类
interface IBaseCRUD<T>{
    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<Person>{
    data: Array<Person> = [] //初始化
    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<T>{
    (val:T,len:number):Array<T>
}

//定义一个符合IGetArr接口的函数--注:必须注明接口的类型
let getArr:IGetArr<any> = function<T>(val:T,len:number){
    let result:T[] = []//默认值为[]
    for(let i = 0; i<len; i++){
        result[i] = val
    }
    return result
}
//调用函数时不能够指定类型,否则会提示错误,因为该函数类型已经是接口类型了
console.log(getArr<string>(\'a\',3))//提示错误
console.log(getArr(\'a\',3))//[\'a\',\'a\',\'a\']
console.log(getArr(123,3))//[123,123,123]

三、泛型类
一个类中的属性值的类型不确定,方法中的参数及返回值类型不确定的情况,可以定义泛型类

//定义一个泛型类
class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; }; 

四、泛型约束
在函数内部使用泛型变量的时候,由于事先不知道它是那种类型,所以不能随意操作它的属性和方法。

function loggingIdentity<T>(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<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);
    return arg;
} 

上例中,我们使用了 extends 约束了泛型 T 必须符合接口 Lengthwise 的形状,也就是必须包含 length 属性。

此时如果调用 loggingIdentity 的时候,传入的 arg 不包含 length,那么在编译阶段就会报错了:

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(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<T extends U, U>(target: T, source: U): T {
    for (let id in source) {
        target[id] = (<T>source)[id];
    }
    return target;
}

let x = { a: 1, b: 2, c: 3, d: 4 };

copyFields(x, { b: 10, d: 20 }); 

上例中,我们使用了两个类型参数,其中要求 T 继承 U,这样就保证了 U 上不会出现 T 中不存在的字段。

以上是关于TypeScript-泛型的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 Typescript 泛型中使用 '&'

TypeScript 入门14.泛型

TypeScript专题之泛型

TypeScript 中泛型的不安全隐式转换

TypeScript——泛型

Typescript 别名泛型接口