最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • TS泛型基础知识 之 萌新总结

    正文概述 掘金(梅利奥猪猪)   2021-02-17   533

    这是一篇本来在假期前就应该总结输出的文章,可惜由于自己太懒,太咸鱼,于是balabalabala(省略几万字的理由)。但真相永远只有一个,就是说多了都是借口,正好假期余额不足了,是时候收心,作为萌新,和大家一起巩固总结下之前看的TS泛型的相关知识,争取输出一篇和各位萌新一看就懂,就能掌握的基础泛型知识文章,大概通过以下三点来说明

    • 在函数中使用泛型
    • 在类中使用泛型
    • 在接口中使用泛型

    在函数中使用泛型

    函数中使用泛型 - 案例一

    先来看这么一段代码

    function join(a: number | string, b: number | string) {
      return `${a} ${b}`;
    }
    

    这是一段很水的代码,作为萌新也一下就能看出来,a和b能传数字也能传字符串,最后的返回值,就是利用字符串模板将两者拼起来,其中我们传值有这么4种可能

    • a数字 b数字
    • a字符串 b字符串
    • a数字 b字符串
    • a字符串 b数字

    但最终的结果依然是拼接,这个时候来了这么个需求,我们必须2个变量的类型要统一,我擦类,这怎么搞,这个时候掏出泛型,改写下代码并这么使用就可以了

    function join<T> (a: T, b: T) {
      return `${a} ${b}`;
    }
    
    join<number>(1, 2);
    join<string>('1', '2');
    // join<number>(1, '2'); //这行报错,你都规定是number了,字符串2是什么鬼
    // join<string>(1, '2'); //这行也报错,你都规定是string了,数字1是什么鬼
    

    在方法执行的括号前加上尖括号,指定类型就可以了(可以省略尖括号,ts会类型推断,但不建议这么做),这样也约束了参数的类型,这就是最基本最基础的一个使用方式了

    函数中使用泛型 - 案例二

    我们同样也可以约束数组每一项的类型,比如写一个最简单的函数,传入个数组,并返回这个数组

    function getArr<T>(arr: T[]) {
      return arr;
    }
    
    getArr<number>([1, 2, 3]) //指定了number,那我的数组必须每一项也是number,如果不是就报错
    getArr<string>(['g', 'q', 'f']) //同理这里指定了string
    

    函数中使用泛型 - 案例三

    获取对象对应key的value,那大家都知道使用obj[key]就可以了,但有的对象我们并不知道有没有这个key,用泛型的话可以很好的解决这个问题

    function getVal<T>(obj: T, k: keyof T){
      return obj[k];
    }
    
    interface Person {
      name: string;
      age: number;
    }
    
    getVal<Person>({
      name: 'gqf',
      age: 29
    }, 'age') // 这里的key值只能传name或者age,否则就会报错,这个就是泛型的力量
    

    函数中使用泛型 - 案例四

    其实我们的案例一可以改造成必须拼接数字和字符串,这里可以使用多个泛型的语法

    function manyTest<K, V>(a: K, b: V) {
      return `${a} ${b}`
    }
    
    manyTest<number, string>(1, '2') //泛型指定了第一个参数是数字,第二个参数是字符串,所以对应的参数也要这么传
    

    在类中使用泛型

    我们来模拟这样一个场景,设计我们的英雄技能吧!

    在类中使用泛型 - 版本一

    初始版本很简单,我们先不用泛型,随意写个类,传入四个技能的数组,并且有个获取技能的方法

    class DesignHero {
      constructor(private skills: string[]){}
    
      getSkill (index: number) {
        console.log(this.skills[index])
        return this.skills[index];
      }
    }
    
    const hero = new DesignHero(['q', 'w', 'e', 'r']) // string[] 所以传入字符串数组
    hero.getSkill(3)
    

    在类中使用泛型 - 版本二

    我们平时不是还喜欢直接用数字来说明技能吗,比如一二三技能,那我们这次改造下,使用数字数组

    class DesignHero {
      constructor(private skills: number[]){} // 这行从string[]改成number[]
    
      getSkill (index: number) {
        console.log(this.skills[index])
        return this.skills[index];
      }
    }
    
    const hero = new DesignHero([1, 2, 3, 4]) // number[] 所以传入数字数组
    hero.getSkill(3)
    

    在类中使用泛型 - 版本三

    写死的方式有点蠢,我们前面不是学了基础的泛型知识吧,那赶紧用泛型改造下案例吧

    class DesignHero<T> {
      constructor(private skills: T[]){}
    
      getSkill (index: number) {
        console.log(this.skills[index])
        return this.skills[index];
      }
    }
    
    const heroNumberSkill = new DesignHero<number>([1, 2, 3, 4]) // 泛型好泛型棒,我可以指定使用数字作为技能描述
    heroNumberSkill.getSkill(1)
    const heroStringSkill = new DesignHero<string>(['q', 'w', 'e', 'r']) // 泛型好泛型棒,我可以指定使用字符串作为技能描述
    heroStringSkill.getSkill(2)
    

    在类中使用泛型 - 版本四

    泛型也可以使用继承,比如只能接受字符串或者数字 <T extends string | number>,具体代码如下

    class DesignHero<T extends string | number> { // 如果把继承的string | number 比如改成boolean, 那下面肯定就报错了
      constructor(private skills: T[]){}
    
      getSkill (index: number) {
        console.log(this.skills[index])
        return this.skills[index];
      }
    }
    
    const heroNumberSkill = new DesignHero<number>([1, 2, 3, 4])
    heroNumberSkill.getSkill(1)
    const heroStringSkill = new DesignHero<string>(['q', 'w', 'e', 'r'])
    heroStringSkill.getSkill(2)
    

    在类中使用泛型 - 版本五

    最终版本,那就是泛型继承接口了,我们可以规定数组中的每一项必须是个对象,且有规定的格式

    interface Skill {
      name: string;
      canDamage: boolean; // 是否是直接造成伤害的技能
    }
    
    class DesignHero<T extends Skill> { // 规定了数组每一项的Skill技能,要遵循接口的格式,有name和canDamage字段
      constructor(private skills: T[]){}
    
      getSkillName (index: number) {
        console.log(this.skills[index].name)
        return this.skills[index].name;
      }
    }
    
    const finalHero = new DesignHero([
      {
        name: '一技能',
        canDamage: true,
      },
      {
        name: '二技能',
        canDamage: false,
      },
      {
        name: '三技能',
        canDamage: false,
      },
      {
        name: '四技能',
        canDamage: true,
      }
    ])
    
    finalHero.getSkillName(0)
    
    

    在接口中使用泛型

    最后我们来学习下接口中的泛型,来模拟下请求响应的场景,初始代码如下

    interface IResponseData{
        code: number;
        message?: string;
        data: any;
    }
    async function getData(url: string){
      let response = await fetch(url);
      let data = await response.json();
      return data;
    } 
    

    上述代码很明显有个问题,我们会发现该接口的data项的具体格式不确定,不同的接口会返回的数据是不一样的,当我们想根据具体当前请求的接口返回具体data格式的时候,就比较麻烦了,因为getData并不清楚你调用的具体接口是什么,对应的数据又会是什么,这个时候我们可以对IResponseData使用泛型,完整代码如下

    interface IResponseData<T>{
        code: number;
        message?: string;
        data: T;
    }
    
    // 用户接口
    interface IResponseUserData{
        id: number;
        username: string;
        email: string;
    }
    
    // 文章接口
    interface IResponseArticleData{
        id: number;
        title: string;
        author: IResponseUserData; 
    } 
    
    async function getData<U>(url: string){
        let response = await fetch(url);
        let data: Promise<IResponseData<U>> = await response.json(); // 注意这里返回的是个Promise,然后我们根据不同的接口,指定不同的data数据格式
        return data;
    } 
    
    (async function(){
        let userData = await getData<IResponseUserData>('/user');
        userData.data.username;
    
        let articleData = await getData<IResponseArticleData>('/article');
        articleData.data.author.email;
    })()  
    

    总结

    其实好像也没什么好总结的,毕竟都是基础知识,也在本文中基本都提到了,如果有什么错误或者遗漏,欢迎大佬们指正,让萌新的我继续变强(是不是太皮了哈哈),最后祝大家好好享受最后的假期,假期过后的工作和摸鱼也都顺顺利利。这里是梅丽奥猪猪,谢谢大家支持~


    起源地下载网 » TS泛型基础知识 之 萌新总结

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元