Typescript的泛型/泛型接口

泛型

  软件工程中,我们不仅要创建一致的定义良好的API,同时要考虑可重用性,组件不仅能够支撑当前的数据类型,同时也能支持未来的数据类型,这在创建大型项目时为你提供了十分灵活的功能, 像C#和java语言中,可以使用范型创建可重用的组件,一个组件可以支持多种类型的数据,这样的用户就可以自己的数据类型来使用组件。通俗来说:泛型就是解决类、接口、方法的复用性、以及不特定数据类型的支持。

泛型的定义和函数

// 只能返回string类型的数据
function getData(value:string):string {
    return value
}

// 同时能返回string类型和number类型, 当要返回string类型时使用getData(冗余)
function getData1(value:number):number {
    return value
}

// ts的其他的方式,实现放回string、number类型
function getData3(value:any):any {
    return value   // 但是有一个问题就是,无法实现类型检查和约束,你也不知道传入和返回是否时一致的
}

// 我们必须要实现一个方法传入什么类型,必须返回什么类型,这就可以使用范型了
function getData4<T>(value:T):T{  // 这里的T就是泛型,这里的T不一定时T,也可以是时A、B、C
    return value  
}

// 使用泛型
alert(getData4<number>(123)) // 约束传入和返回的类型为number
getData4<string>('1111')  // 约束传入和返回的类型为string


function getData5<T>(value:T):any{  // 这里的T就是泛型,返回值为any
    return value  
}

getData5<string>('1111')

  

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

class MinClass {
    public list:number[]=[];

    add(num:number){
        this.list.push(num);
    }

    min():number{
        var minNum = this.list[0];
        for (var i=0; i<this.list.length;i++){
            if (minNum>this.list[i]){
                minNum = this.list[i];
            }
        }
        return minNum
    }
}

var m = new MinClass();
m.add(2);
m.add(12);
m.add(33);
m.add(52);
alert(m.min())

// 上面的代码是可以传入数值返回最小值,那如果我想传入a-z的字符,能否返回其中最小的
class MinClass1<T> {  // 泛型类
    public list:T[] = [];
    add(value:T):void {
        this.list.push(value)
    }

    min():T{
        var minNum = this.list[0];
        for (var i=0; i<this.list.length;i++){
            if (minNum>this.list[i]){
                minNum = this.list[i];
            }
        }
        return minNum
    }
}

var m1 = new MinClass1<string>();  // 这里的泛型是string,当然也可以是number
m1.add('a');
m1.add('A')
m1.add('b')
alert(m1.min())

  

泛型接口

// 函数类型接口
interface ConfigFn {
    (value1:string,value2:string):string  // 函数接口
}

var setData:ConfigFn = function(value1:string, value2:string):string{
    return value1+value2
}
alert(setData('name','wangwu'))  // 韩式类型接口实现

// 第一种定义方式:泛型接口 
interface ConfigFns {
    <T>(value1:T):T;  // 泛型接口
}

var getData:ConfigFns = function<T>(value1:T):T{
    return value1
}

getData<string>("OK")

// 第二种定义方式
interface ConfigFnplus<T> {
    (value1:T):T;  // 泛型接口
}

function getData1<T>(value1:T):T{
    return value1
}

var myGetData:ConfigFnplus<string> = getData1
myGetData("OK,wo")

  

泛型小demo:

  功能: 定义一个操作数据库的库,支持Mysql、 Mssql、Mongdb,要求Mysql、Mssql、Mongdb功能一样,都有add、update、delete、get方法

注意:约束统一规范,以及代码的重用,解决方案:需要约束规范所以要定义接口,接口是一种规范定义,它定义了行为和动作的规范;泛型通俗理解:泛型就是解决类、接口方法的复用性。

// 定义接口
interface DBI<T>{
    add(info:T):boolean;
    update(info:T,id:number):boolean;
    delete(id:number):boolean;
    get(id:number):any[];
}    


// 实现mongdb类
class MongDb<T> implements DBI<T> {
    add(info: any): boolean {
        console.log(info)
        return true
    }
    update(info: any, id: number): boolean {
        throw new Error("Method not implemented.");
    }
    delete(id: number): boolean {
        throw new Error("Method not implemented.");
    }
    get(id: number): any[] {
        throw new Error("Method not implemented.");
    }
    
}

// 定义一个操作mysql数据库的类,注意:要实现泛型接口,这个类应该是一个泛型类
class MysqlDb<T> implements DBI<T>{

    constructor(){
        console.log('数据库实现连接')
    }
    add(info: T): boolean {
        console.log(info)
        return true
    }
    update(info: T, id: number): boolean {
        throw new Error("Method not implemented.");
    }
    delete(id: number): boolean {
        throw new Error("Method not implemented.");
    }
    get(id: number): any[] {
        throw new Error("Method not implemented.");
    }

}  

// 操作用户表, 定义一个user类和数据表做映射
class User{
    username:string|undefined;
    password:string|undefined;
}

var u = new User();
u.username='张三';
u.password='123'

//var oMysql = new MysqlDb();  // 类作为参数约束数据传入的类型
var oMysql = new MysqlDb<User>();  // 通过指定类型去校验参数

oMysql.add(u); // 这里的u是实现了验证的