zoukankan      html  css  js  c++  java
  • 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("张三", "李四");

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

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

    使用 类,接口,泛型, 实现SQL底层封装

      sql 数据库类的简单功能有: 查询, 添加, 修改, 删除 ,先从这四个功能起封装库类, 先定义一个泛型接口

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

      简单实现接口, 注意: 要实现泛型接口, 这个类也是必须是泛型类

    // 定义一个操作mysql数据库类, 实现接口, 注意要实现泛型接口, 这个类也是泛型类
    class MysqlDb<T> implements DBI<T> {
        constructor() {
            // 数据库建立连接-------
          }
    
        add(info: T): boolean {
            throw new Error("Method not implemented.");
        }
        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.");
        }
       
    }
    
    // 实现sqlserver 的数据库类
    class SqlserverDb<T> implements DBI<T> {
        constructor() {
            // 数据库建立连接-------
         }
    
        add(info: T): boolean {
            throw new Error("Method not implemented.");
        }
        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.");
        }
       
    }

    实现mysql数据类操作User数据表,, 使用泛型, 把类当作参数来约束方法

    // 定义实体类, 映射数据库表的类
    class User{
        id: number | undefined;
        userName:string | undefined;
        password:string | undefined;
    }
    
    var user = new User();
    user.id = 1;
    user.userName = "tom";
    user.password = "12345678";
    
    
    // 实现user类的数据库操作
    var UserMysql = new MysqlDb<User>();
  • 相关阅读:
    VB.net和c#利用IOleCommandTarget接口实现Html编辑器的Glyphs(原创)
    vb.net中用com通讯实现对HTMLDocument的事件捕捉(原创)
    自己写的用JS脚本定时执行Web地址并且得到它的源代码的页面程序
    Alice:曾经的CS反恐精英顶尖高手
    .net利用IOleCommandTarget接口实现Html编辑器表格边框的显示和隐藏(原创)
    ASP用语法及函数
    最近在研究质量统计与分析方面的项目开发
    propertyGrid实现选项(原创)
    .Net平台AOP技术研究
    c# propertyGrid属性控件跟Htmlelement元素绑定(原创精华)
  • 原文地址:https://www.cnblogs.com/yangWanSheng/p/15417092.html
Copyright © 2011-2022 走看看