六、TypeScript中的泛型

139 阅读2分钟

泛型的定义

解决类,接口 方法的复用性,以及对不特定数据类型的支持

泛型函数

function getData(value: string):string {
    return value;
}

只能返回string类型的数据

如果想同时返回string和number类型的数据可以定义类型为any

但是any相当于放弃了类型检查,并且传入参数类型和返回参数类型可以不一致

function getAnyData(value: any):any {
    return value;
}

使用泛型,传入的类型必须和返回的类型一致

function getTData<T>(value:T):T{
    return value;
}
//指定参数必须是<>里面的类型
getTData<number>(123);
getTData<string>('4545');

泛型类

比如有一个返回最小值算法,需要同时支持返回数字和字符串类型,通过类的泛型来实现

普通的实现:

class MinClass {
    list:number[] = [];
    add(num:number) {
        this.list.push(num);
    }
    min():number {
        let min:number = this.list[0];
        this.list.forEach((item:number) => {
            if(item<min){
                min = item;
            }
        })
        return min;
    }
}
var m = new MinClass();
m.add(25);
m.add(21);
m.add(13);
m.add(12);
console.log(m.min());

只能传入number类型,返回number类型。

泛型的实现:

class MinClass<T> {
    list:T[] = [];
    add(num:T):void {
        this.list.push(num);
    }
    min():T {
        let min = this.list[0];
        this.list.forEach((item) => {
            if(item < min){
                min = item;
            }
        })
        return min;
    }
}
//实例化类,并指定了类的T代表的类型
var m2 = new MinClass<string>();
m2.add('a');
m2.add('c');
m2.add('b');
m2.add('d');
console.log(m2.min());

可以在实例化的时候指定不同的类型

泛型接口

回顾一下普通函数接口

interface ConfigFn{
    (value:string,value2:string):string;
}
var setData: ConfigFn = function(value:string,value2:string):string {
    return value+value2;
}

泛型函数接口

第一种写法

interface ConfigFn{
    <T>(value:T):T;
}
var getData: ConfigFn = function<T>(value:T):T {
    return value;
}
getData<string>('12346')
// getData<string>(12346);//错误写法

第二种写法

interface ConfigFn<T>{
    (value:T):T;
}
function getData<T>(value:T):T {
    return value;
}
// 调用这个接口的时候指定泛型为string类型
var myGetData:ConfigFn<string>=getData;
myGetData('15')
myGetData(15);//错误写法

把类当做参数的泛型类

class Article {
    title: string | undefined;
    desc: string | undefined;
    status: number | undefined;
    id: number | undefined;
}

class  DB {
    add(info: Article):boolean{
        console.log(info);
        return true;
    }
}

let db = new DB();
let news = new Article();
news.title = "China";
news.desc = "Chinese";
news.status = 1;
console.log(db.add(news))

为了避免调用add方法传入不同类型的实参都要修改DB类的add的形参类型,使用泛型

class  DB2<T> {
    add(info: T):boolean{
        console.log(info);
        return true;
    }
    update(info:T,id:number): boolean{
        info['id'] = id;
        console.log(info);
        return true;
    }
}
// <Article>对传入数据进行校验
let db2 = new DB2<Article>();
db2.add(news)

定义类作为参数来约束传入的类型,不同类型的class调用add方法只需要在实例化的时候指定要传入的类型,不用再修改add方法的形参类型。

class ArticleCate {
    titleCate: string |undefined;
    descCate: string |undefined;
    statusCate: number |undefined;
    idCate:number|undefined;

    constructor(params:{
        titleCate: string |undefined,
        descCate: string |undefined,
        statusCate?: number |undefined
        idCate?: number |undefined
    }){
        this.titleCate = params.titleCate;
        this.descCate = params.descCate;
        this.statusCate = params.statusCate;
    }
}

var ac = new ArticleCate({
    titleCate: 'China',
    descCate: 'China desc'
});
// 把类当做参数传入泛型类,泛型类对传入的参数做校验
let db3 = new DB2<ArticleCate>();
console.log(db3.add(ac))// ArticleCate {title: "China", desc: "China desc", status: undefined}
console.log(db3.update(ac,123))// ArticleCate {title: "China", desc: "China desc", status: undefined, id: 123}