微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

TypeScript学习: 九、TypeScript的泛型

泛型的定义

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

泛型函数

 有一个需求: 传入指定的参数类型 返回这个指定的参数类型    比如 要求参数类型是 string 返回 string  要求参数类型是 number返回 number

// 只能返回string 的函数
function getData(val:string):string{
return val + "返回字符串";
}
//  只能返回number 的函数
function getData1(val:number):number{
    return val; // 返回数字
}

 

  这里用了两个函数去实习功能,如果还需要返回  bloolean 类型是不是还需要再添加一个函数去实现, 这样实现的话会出现了代码的冗余

 有人就会想到用any类型去实现功能

function getData2(val:any):any{
    return 123; // 返回number
}
getData2("string");

  用any可以实现功能, 但是会出现这样的错误, 我传入string类型, 返回了number ,不符合要求, 并且使用any类型就是抛弃typeScript的初衷了,放弃了类型检查

使用泛型解决问题:泛型可以支持不特定类型, 实现要求传入类型和返回的类型一致

 // T 表示泛型, 具体什么类型是调用的时候决定的
function getData<T>(val:T):T{
    return val;
}
// 调用:
// number类型, 返回number 类型
getData<number>(100);

// string 类型
getData<string>("张三");

getData<boolean>(123); // 错误写法 定义Boolean类型,不能传入number类型的参数

 

 如果要求函数返回必须为string类型的 泛型函数写法:

 // 泛型函数, 指定返回string类型
function getData<T>(val:T):string{
    return val + "val";
}

getData<number>(234);

getData<string>("张三");

 

通过这两个例子可以看出 泛型 T 代表的是一种数据类型, 具体是什么数据类型,就是要调用方法的时候传入指定的类型来确定的 。 

 getData<T>     getData<string>     该函数里面的所有T 都是泛型 

泛型类

需求:比如有个最小的堆算法, 需要同时支持返回数字和字符串两种类型,  通过类的泛型来实现
// 不适用泛型类的写法
class MinClass{
    public list:number[] = [];

    add(num:number):void{
        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(50);
m.add(1);
console.log(m.min());  // 输出: 1

 这个列子可以实现的是number类型的最小堆算法,对于类型校验,不能使用string的类型

看看 泛型类的实现

// 泛型类
class MinClass<T>{
    public list:T[] = [];

    add(num:T):void{
        this.list.push(num);
    }
    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 m = new MinClass<number>(); // 实例化 类, 并且指定了泛型 的类型 为number
m.add(2);
m.add(50);
m.add(1);
console.log(m.min());  // 输出: 1

var s = new MinClass<string>();
s.add("n");
s.add("a");
s.add("z");
console.log(s.min());  // 输出: a    码值计算

使用泛型了, 可以写入number类型和string类型 

 

--- 泛型类--- 进阶

  要求:定义一个类,把类当作参数,来约束传入的数据类型

  实现:定义一个user的类,这个类的作用是映射数据库字段, 然后定义个MysqLDb的类,用于操作数据库,然后把User类当作参数传入到MysqLDb执行

// 映射数据库字段的实体类
class User{
    public username:string | undefined;
    public pasword:string | undefined;

    constructor() {

    }
}

// 数据库操作类型
class MysqLDb{
    // 添加数据
    add(user:User):boolean{
        return true;
    }
    // 删除数据
    // 修改数据
    // ----
}

var u = new User();
u.username = "张三";
u.pasword = "123";

var Db = new MysqLDb();

Db.add(u);  // 把这个user添加数据库

 

 这个 MysqLDb 可以执行 user类 的添加等操作, 同样的问题:这个MysqLDb 只能对user 类进行操作, 如果我还有其他的表:

 

class ArticleCate{
    title:string | undefined;
    desc:string | undefined;
    status:number | undefined;
    constructor() {

    }
}
// 数据库操作类型
class MysqLDb{
    // 添加数据
    add(info:ArticleCate):boolean{
        console.log(info);
        return true;
    }
    // 删除数据
    // 修改数据
    // ----
}
var art = new ArticleCate();
art.status = 1;
art.desc = "国内新闻";
art.title = "国内";
var Db = new MysqLDb();
Db.add(art);  // 把这个ArticleCate添加数据库

是不是这样就出现了代码的冗余, 有多个要操作的实体类,就要定义多个  MysqLDb 去实现

来看看泛型如何实现, 把 MysqLDb  就封装一次

// 映射数据库字段的实体类
class User{
    public username:string | undefined;
    public pasword:string | undefined;

    constructor() {

    }
}

class ArticleCate{
    title:string | undefined;
    desc:string | undefined;
    status:number | undefined;
    constructor() {

    }
}

var art = new ArticleCate();
art.status = 1;
art.desc = "国内新闻";
art.title = "国内";
var DbArt = new MysqLDb<ArticleCate>(); // 直接实例化 MysqLDb
DbArt.add(art);  // 把这个ArticleCate添加数据库中

var user = new User();
user.username = "张三";
user.pasword = "24123";
var DbUser = new MysqLDb<User>();
DbUser.add(user); // 把这个User添加数据库中
// DbUser.add(123); // 错误写法, 有类型校验

 

所以泛型, 不仅可以代表基本数据类型, 也可以是定义的类

 

泛型接口

先来看一个函数接口

 // 函数接口
interface ConfigFn{
    (val: string, val2: string):string;
}
// 实现接口
var getData:ConfigFn = function(val1:string, val2:string):string{
    return val1 + val2;
}

var str:string = getData("张三", "李四");

console.log(str);

 

 再来看看泛型接口

 // 泛型函数接口
interface ConfigFn{
    <T>(val: T, val2: T):T;
}
// 实现泛型函数接口
var getData:ConfigFn = function<T>(val1:T, val2:T):T{
    return val1;
}

var str:string = getData<string>("张三", "李四");

console.log(str);

 

 实现泛型接口的时候, 不指定泛型类型, 到调用的时候再指定类型

另外一种写法

// 泛型函数接口的另外一种写法
interface ConfigFn<T> {
    (val: T, val2: T):T;
}

// 定义函数
function getData<T>(val1:T, val2:T):T{
    return val1;
}
// 实现接口, 并且指定类型
var myGetData:ConfigFn<string> = getData; 

myGetData("张三", "李四");

注意: 实现泛型接口,本身也要是一个泛型

 

 

有了泛型, 调用方法的时候,同样的代码,可供多个类型使用,大大的扩展了代码的复用性 

 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐