1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
      <output id="hzk7v"></output>
    2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
    3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>

      TypeScript中的方法重载详解

       更新时间£º2019年04月12日 11:20:28   作者£º刘哇勇   我要评论

      这篇文章主要给大家介绍了关于TypeScript中方法重载的相关资料£¬文中通过示例代码介绍的非常详细£¬对大家学习或者使用TypeScript具有一定的参考学习价值£¬需要的朋友们下面来一起学习学习吧

      前言

      方法重载£¨overload£©在传统的静态类型语言中是很常见的¡£JavaScript 作为动态语言£¬ 是没有重载这一说的¡£一是它的参数没有类型的区分£¬二是对参数个数也没有检查¡£虽然语言层面无法自动进行重载£¬但借助其动态的特性£¬我们可以在代码中手动检查入参的类型£¬或者通过 arguments 获取到参数个数£¬从而实现根据不同的入参做不同的操作¡£

      比如有一个获取聊天消息的方法£¬根据传入的参数从数组中查找数据¡£如果入参为数字£¬则认为是 id£¬然后从数据源中找对应 id 的数据并返回£¬否则当成类型£¬返回这一类型的消息¡£

      function getMessage(query) {
       if (typeof query === "nunber") {
       return data.find(message => message.id === query);
       } else {
       return data.filter(message => message.type === query);
       }
      }

      TypeScript 中£¬假如我们的消息数据为如下结构£º

      type MessageType = "string" | "image" | "audio";
      
      type Message = {
       id: number;
       type: MessageType;
       content: string;
      };

      上面获取数据的方法等价于£º

      function getMessage(
       query: number | MessageType
      ): Message[] | Message | undefined {
       if (typeof query === "number") {
       return data.find(message => message.id === query);
       } else {
       return data.filter(message => message.type === query);
       }
      }

      这样做一是类型书写上比较丑陋£¬二是没有发挥出 TypeScript 类型检查的优势£¬这里我们是可以根据入参的类型明确知道返回的类型的£¬即如果传入的是 id£¬返回的是单个数据或undefined£¬如果是根据类型查找£¬返回的是数组¡£而现在调用方法后£¬得到的类型太过宽泛£¬这和使用 any 做为返回没多大差别¡£

      函数返回类型不够紧凑

      因为类型的不明朗£¬返回的结果都不能直接操作£¬需要进行类型转换后才能继续¡£

      const result1 = getMessage("audio");
      /** 不能直接对 result1 调用数组方法 */
      console.log((result1 as Message[]).length);
      
      const result2 = getMessage(1);
      if (result2) {
       /** 不能对 result2 直接访问消息对象中的属性 */
       console.log((result2 as Message).content);
      }

      重载的实现

      这时候可通过提供多个函数类型的声明来解决上面的问题£¬最后得到的结果就是间接实现了函数的重载¡£当然这个重载只是 TypeScript 编译时的¡£

      function getMessage(id: number): Message | undefined;
      function getMessage(type: MessageType): Message[];
      function getMessage(query: any): any {
       if (typeof query === "number") {
        return data.find(message => message.id === query);
       } else {
        return data.filter(message => message.type === query);
       }
      }

      这样?#33041;?#21518;£¬我们在调用的时候直接就会有重载的提示¡£

      实现 TypeScript 的重载后调用时的自动提示

      并且得到的结果类型是重载方法中指定的入参与返回的组合£¬在对结果进行使用时£¬无须再进行类型转换¡£

      const result1 = getMessage("audio");
      /** ✅ 无须类型转换 */
      console.log(result1.length);
      
      const result2 = getMessage(1);
      if (result2) {
       /** ✅ 无须类型转换 */
       console.log(result2.content);
      }

      这里需要理解的是£¬上面添加的函数类型仅作为 TypeScript 在编译时使用的£¬它不是真的实现像传统静态类型语言那样的重载£¬也不会改变编译后代码的输出¡£?#23548;?#36816;行时仍然是不带重载的 JavaScript 版本¡£

      编译后的代码

      但这一点也不影响我们在 TypeScript 中使用这种假的重载¡£

      可选参数

      另一个 TypeScript 重载的场景¡£还?#24039;?#38754;获取消息数据的方法£¬因为根据类型查找消息时£¬会返回同类型消息的一个数组¡£此时我们想加一个参数实现只返回结果中前几个数据£¬那么可以很方便地进行如下的?#33041;še?/p>

      function getMessage(id: number): Message | undefined;
      +function getMessage(type: MessageType, count?: number): Message[];
      +function getMessage(query: any, count = 10): any {
       if (typeof query === "number") {
        return data.find(message => message.id === query);
       } else {
      +  return data.filter(message => message.type === query).splice(0, count);
       }
      }

      通过重载£¬这个新增的参数很容?#36164;?#29616;只针对入参 MessageType 时£¬这样如果我们有如下的调用£¬会得到编译时的报错£º

      /** 🚨 Argument of type '1' is not assignable to parameter of type 'MessageType' */
      getMessage(1,10);

      而非重载的版本是享受不到上面提到的类型优势的¡£

      function getMessage(
       query: number | MessageType,
       count = 10
      ): Message[] | Message | undefined {
       if (typeof query === "number") {
        return data.find(message => message.id === query);
       } else {
        return data.filter(message => message.type === query).splice(0, count);
       }
      }
      
      /** ✅ ojbk, 不错报 */
      getMessage(1, 10);

      重载过程

      TypeScript 重载的过程是£¬拿传入的参数和重载的方法签名列表中由上往下逐个匹配£¬直到找到一个完全匹配的函数签名£¬否则报错¡£所以推荐的做法是将签名更加具体的重载放上面£¬不那么具体的放后面¡£

      /** ✅*/
      function getMessage(type: MessageType, count?: number): Message[];
      function getMessage(id: number): Message | undefined;
      
      /** 🚨*/
      function getMessage(id: number): Message | undefined;
      function getMessage(type: MessageType, count?: number): Message[];

      像上面示例中正确做法这样£¬如果说入参个数只有一个£¬那可以直接跳过第一个函数签名£¬无须做入参类型的判断¡£

      相关资源

      总结

      以上就是这篇文章的全部内容了£¬希望本文的内容对大家的学习或者工作具有一定的参考学习价值£¬谢谢大家对脚本之家的支持¡£

      相关文章

      最新评论

      3dÊÔ»úºÅÖвÊÍø

        1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
          <output id="hzk7v"></output>
        2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
        3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>

            1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
              <output id="hzk7v"></output>
            2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
            3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>