前言

方法重载(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");
/** "color: #ff0000">可选参数

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

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

通过重载,这个新增的参数很容易实现只针对入参 MessageType 时,这样如果我们有如下的调用,会得到编译时的报错:

/** "htmlcode">
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);
 }
}

/** "color: #ff0000">重载过程

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

/** "external nofollow" target="_blank" href="https://www.typescriptlang.org/docs/handbook/functions.html">TypeScript Handbook - Functions - Overloads
  
  • Typescript method overloading
  • 总结

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

    华山资源网 Design By www.eoogi.com
    广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
    免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
    华山资源网 Design By www.eoogi.com

    《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线

    暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。

    艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。

    《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。