TypeScript中的方法重载详解


Posted in Javascript onApril 12, 2019

前言

方法重载(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 做为返回没多大差别。

TypeScript中的方法重载详解

函数返回类型不够紧凑

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

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);
 }
}

这样改造后,我们在调用的时候直接就会有重载的提示。

TypeScript中的方法重载详解

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

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

const result1 = getMessage("audio");
/** ✅ 无须类型转换 */
console.log(result1.length);

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

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

编译后的代码

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

可选参数

另一个 TypeScript 重载的场景。还是上面获取消息数据的方法,因为根据类型查找消息时,会返回同类型消息的一个数组。此时我们想加一个参数实现只返回结果中前几个数据,那么可以很方便地进行如下的改造:

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);
 }
}

通过重载,这个新增的参数很容易实现只针对入参 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[];

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

相关资源

  • TypeScript Handbook - Functions - Overloads
  • Typescript method overloading

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
javascript Window及document对象详细整理
Jan 12 Javascript
js获取html文件的思路及示例
Sep 17 Javascript
JavaScript1.6数组新特性介绍以及JQuery的几个工具方法
Dec 06 Javascript
浅谈jQuery中对象遍历.eq().first().last().slice()方法
Nov 26 Javascript
javascript工厂方式定义对象
Dec 26 Javascript
jQuery表单域选择器用法分析
Feb 10 Javascript
jquery实现顶部向右伸缩的导航区域代码
Sep 02 Javascript
jQuery实现为控件添加水印文字效果(附源码)
Dec 02 Javascript
jQuery旋转插件jqueryrotate用法详解
Oct 13 Javascript
Angularjs 设置全局变量的方法总结
Oct 20 Javascript
vue.js数据绑定的方法(单向、双向和一次性绑定)
Jul 13 Javascript
微信小程序实现动态获取元素宽高的方法分析
Dec 10 Javascript
vue-cli 3.x配置跨域代理的实现方法
Apr 12 #Javascript
解决微信小程序调用moveToLocation失效问题【超简单】
Apr 12 #Javascript
详解Bootstrap 学习(一)入门
Apr 12 #Javascript
vue组件中iview的modal组件爬坑问题之modal的显示与否应该是使用v-show
Apr 12 #Javascript
vue+echarts实现可拖动节点的折线图(支持拖动方向和上下限的设置)
Apr 12 #Javascript
详解Vue中使用插槽(slot)、聚类插槽
Apr 12 #Javascript
JS实现li标签的删除
Apr 12 #Javascript
You might like
PHP输出英文时间日期的安全方法(RFC 1123格式)
2014/06/13 PHP
php中使用in_array() foreach array_search() 查找数组是否包含时的性能对比
2015/04/14 PHP
PHP实现的线索二叉树及二叉树遍历方法详解
2016/04/25 PHP
PHP树-不需要递归的实现方法
2016/06/21 PHP
解决form中action属性后面?传递参数 获取不到的问题
2017/07/21 PHP
基于jquery的一行代码轻松实现拖动效果
2010/12/28 Javascript
jQuery获取CSS样式中的颜色值的问题,不同浏览器格式不同的解决办法
2013/05/13 Javascript
javascript字符串替换及字符串分割示例代码
2013/12/12 Javascript
javascript生成随机大小写字母的方法
2014/02/20 Javascript
JavaScript截取、切割字符串的技巧
2016/01/07 Javascript
JS实现上下左右对称的九九乘法表
2016/02/22 Javascript
JS控制层作圆周运动的方法
2016/06/20 Javascript
jQuery基于BootStrap样式实现无限极地区联动
2016/08/26 Javascript
简单几步实现返回顶部效果
2016/12/05 Javascript
Javascript this 函数深入详解
2016/12/13 Javascript
bootstrap modal弹出框的垂直居中
2016/12/14 Javascript
jQuery Easyui datagrid行内实现【添加】、【编辑】、【上移】、【下移】
2016/12/19 Javascript
angular.js+node.js实现下载图片处理详解
2017/03/31 Javascript
使用html+js+css 实现页面轮播图效果(实例讲解)
2017/09/21 Javascript
获取本机IP地址的实例(JavaScript / Node.js)
2017/11/24 Javascript
jQuery实现判断上传图片类型和大小的方法示例
2018/04/11 jQuery
angularjs结合html5实现拖拽功能
2018/06/25 Javascript
js实现简易点击切换显示或隐藏
2020/11/29 Javascript
[02:16]完美世界DOTA2联赛PWL S3 集锦第三期
2020/12/21 DOTA
Python类的用法实例浅析
2015/05/27 Python
Python实现自动添加脚本头信息的示例代码
2016/09/02 Python
Python用csv写入文件_消除空余行的方法
2018/07/06 Python
python json.loads兼容单引号数据的方法
2018/12/19 Python
对tensorflow中tf.nn.conv1d和layers.conv1d的区别详解
2020/02/11 Python
巴西最大的珠宝连锁店:Vivara
2019/04/18 全球购物
Furla官网:意大利著名的皮革品牌
2019/08/06 全球购物
集团公司总经理岗位职责
2013/12/20 职场文书
教师辞职报告范文
2014/01/20 职场文书
医务工作者先进事迹材料
2014/01/26 职场文书
市委常委会班子党的群众路线教育实践活动整改方案
2014/10/25 职场文书
关于的python五子棋的算法
2022/05/02 Python