问题:
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 声明函数重载内容请搜索阿兔在线工具以前的文章或继续浏览下面的相关文章希望大家以后多多支持阿兔在线工具!