TypeScript 使用 Tuple Union 声明函数重载


Posted in Javascript onApril 07, 2022

问题:

TypeScript 中为函数添加多个签名后,依然需要添加相应的代码来判断并从不同的签名参数列表中获取对应的参数。过去常见的写法:

function refEventEmitter(event?: string): void;
function refEventEmitter(event: string, callback: () => void): void;
function refEventEmitter(callback: () => void): void;
function refEventEmitter(
  eventOrCallback?: string | (() => void),
  callback?: () => void,
): void {
  let event: string | undefined;

  if (typeof eventOrCallback === 'function') {
    callback = eventOrCallback;
  } else {
    event = eventOrCallback;
  }

  // ...
}

这个过程因为将原有参数列表直接按序号拍平,参数之间的类型关联需要人肉确保正确。

技巧:

这时我们可以通过使用tuple union 的参数类型,来无脑处理各种函数重载情况:

function refEventEmitter(event?: string): void;
function refEventEmitter(event: string, callback: () => void): void;
function refEventEmitter(callback: () => void): void;
function refEventEmitter(
  ...args:
    | [event?: string]
    | [
        event: string,
        callback: () => unknown,
      ]
    | [callback: () => unknown]
): void {
  let [event, callback] =
    args.length === 2
      ? args
      : typeof args[0] === 'function'
      ? [undefined, args[0]]
      : [args[0], undefined];

  // ...
}

实际上,此时上方的签名列表也不再需要了:

function refEventEmitter(
  ...args:
    | [event?: string]
    | [
        event: string,
        callback: () => unknown,
      ]
    | [callback: () => unknown]
): void {
  let [event, callback] =
    args.length === 2
      ? args
      : typeof args[0] === 'function'
      ? [undefined, args[0]]
      : [args[0], undefined];

  // ...
}
这篇其实拖了有点久,在写的时候发现 TypeScript 已经内置了 "Convert overload list to single signature" 的重构选项,可以一键将重载列表变为参数 tuple union。

不过到这里其实还存在问题,TypeScript 中 typeof 条件判断不能对整个对象进行收窄,只能收窄被 typeof 到的某个元素、属性。上面的例子中,如果需要的不只是 args[0] 就会出现问题。

此时我们可以引入一个工具函数 isTypeOfProperty(object, key, type)

此时实现就变成了:

function refEventEmitter(
  ...args:
    | [event?: string]
    | [
        event: string,
        callback: () => unknown,
      ]
    | [callback: () => unknown]
): void {
  let [event, callback] =
    args.length === 2
      ? args
      : isTypeOfProperty(args, 0, 'function')
      ? [undefined, args[0]]
      : [args[0], undefined];

  // ...
}

到此这篇关于TypeScript 使用 Tuple Union 声明函数重载的文章就介绍到这了,更多相关TypeScript 声明函数重载内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
5个javascript的数字格式化函数分享
Dec 07 Javascript
jQuery+css实现图片滚动效果(附源码)
Mar 18 Javascript
javascript删除option选项的多种方法总结
Nov 22 Javascript
浅谈jQuery中对象遍历.eq().first().last().slice()方法
Nov 26 Javascript
JavaScript操作Cookie方法实例分析
May 27 Javascript
Javascript中函数名.length属性用法分析(对比arguments.length)
Sep 16 Javascript
jQuery中checkbox反复调用attr('checked', true/false)只有第一次生效的解决方法
Nov 16 Javascript
深入理解vue.js双向绑定的实现原理
Dec 05 Javascript
Js apply方法详解
Feb 16 Javascript
详解ES6之async+await 同步/异步方案
Sep 19 Javascript
微信小程序scroll-view横向滑动嵌套for循环的示例代码
Sep 20 Javascript
浅谈Vue3 Composition API如何替换Vue Mixins
Apr 29 Javascript
Axios代理配置及封装响应拦截处理方式
vue-cil之axios的二次封装与proxy反向代理使用说明
Apr 07 #Vue.js
动态规划之使用备忘录来改进Javascript函数
Apr 07 #Javascript
vue实现拖拽交换位置
Apr 07 #Vue.js
使用Ajax实现进度条的绘制
Vue.Draggable实现交换位置
vue-cli3.0修改打包后的文件名和文件地址,打包后本地运行报错解决
You might like
php中截取字符串支持utf-8
2007/01/18 PHP
php 生成文字png图片的代码
2011/04/17 PHP
一个典型的PHP分页实例代码分享
2011/07/28 PHP
php中ob_flush函数和flush函数用法分析
2015/03/18 PHP
php递归删除指定文件夹的方法小结
2015/04/20 PHP
详解PHP的Yii框架中的Controller控制器
2016/03/29 PHP
深入理解PHP中mt_rand()随机数的安全
2017/10/12 PHP
php pdo连接数据库操作示例
2019/11/18 PHP
简单的js分页脚本
2009/05/21 Javascript
JQuery UI皮肤定制
2009/07/27 Javascript
defer属性导致引用JQuery的页面报“浏览器无法打开网站xxx,操作被中止”错误的解决方法
2010/04/27 Javascript
非html5实现js版弹球游戏示例代码
2013/09/22 Javascript
JavaScript怎么判断图片是否加载完成以便获取其尺寸
2014/05/08 Javascript
JQuery悬停控制图片轮播——代码简单
2015/08/05 Javascript
详解XMLHttpRequest(一)同步请求和异步请求
2016/09/14 Javascript
javascript 动态样式添加的简单实现
2016/10/11 Javascript
jquery实现tab键进行选择后enter键触发click行为
2017/03/29 jQuery
js获取浏览器的各种属性
2017/04/27 Javascript
Vue+Flask实现简单的登录验证跳转的示例代码
2018/01/13 Javascript
vue计算属性时v-for处理数组时遇到的一个bug问题
2018/01/21 Javascript
详解微信小程序调起键盘性能优化
2018/07/24 Javascript
javascript设计模式 ? 装饰模式原理与应用实例分析
2020/04/14 Javascript
解决vue-router路由拦截造成死循环问题
2020/08/05 Javascript
three.js显示中文字体与tween应用详析
2021/01/04 Javascript
[02:21]DOTA2英雄基础教程 蝙蝠骑士
2013/12/16 DOTA
[03:55]DOTA2完美大师赛选手传记——LFY.MONET
2017/11/18 DOTA
修改Python的pyxmpp2中的主循环使其提高性能
2015/04/24 Python
简单介绍Python的Django框架的dj-scaffold项目
2015/05/30 Python
Python 字符串大小写转换的简单实例
2017/01/21 Python
python实现文字版扫雷
2020/04/24 Python
波兰最大的宠物用品网上商店:FERA.PL
2019/08/11 全球购物
Linux常见面试题
2013/03/18 面试题
常见的软件开发流程有哪些
2015/11/14 面试题
环保倡议书怎么写
2014/05/16 职场文书
关于有小孩的离婚协议书
2014/10/26 职场文书
python opencv旋转图片的使用方法
2021/06/04 Python