[英]Wrapping an Overloaded Typescript Function
我在为重载函数编写包装器时遇到问题。
我包装的功能是SendGrid 电子邮件发送功能。 该函数被重载(简化):
declare class MailService {
send(data: Email): foo;
send(data: Email[]): foo;
}
我想编写一个可以接受Email
或Email[]
的函数。 但是当我这样做时,它抱怨没有过载匹配调用:
function sendEmailWrapper1(data: Email | Email[]) {
sendGrid.send(data)
}
但是,这有效:
function sendEmailWrapper2(data: Email | Email[]) {
if ('length' in data) {
sendGrid.send(data)
} else {
sendGrid.send(data)
}
}
我认为正在发生的事情是Email | Email[]
Email | Email[]
不是send(data: Email)
或send(data: Email[])
的有效输入,Typescript 没有意识到重载意味着sendGrid.send(data)
应该是有效的(并且,实际上,如果if
和else
分支可以具有相同的代码并且是有效的,那么即使没有if
语句来帮助它推断类型,Typescript 似乎也应该能够意识到该语句是有效的,因为 Typescript 是编译时只是并且实际上不会指导运行时代码执行根据类型进行不同的函数调用)。
我的两个问题:
sendEmailWrapper1
无法编译但sendEmailWrapper2
可以工作?谢谢!
这是class MailService
声明的一个缺点。 它可以有一个更准确的类型定义,如下所示:
declare class MailService {
send(data: Email | Email[]): foo;
}
在我看来,最佳实践是在本地增加类型定义。 然后向存储库提交一个包含更改的拉取请求。
此外,这是一个使用 rest 参数的包装器。 它将以更少的努力工作:
// Accepts on or more MailData objects.
// sendEmailWrapper3(data);
// sendEmailWrapper3(data, data1);
function sendEmailWrapper3(...data: MailData[]) {
sendGrid.send(data);
}
实际上这种用法并不是重载的好例子,如果你需要重载方法,就意味着当参数类型改变时你需要返回不同的类型。 如果您需要不同的返回类型,则重载方法更加一致。 例如 :
send(data: Email): foo;
send(data: Email[]): foo[]
或者如果参数有一个可选的属性,但是当设置了该属性时,则必须需要另一个属性。
function bar(params:{
prop1: number;
prop2?: boolean;
}): Foo;
function bar(params:{
prop1: number;
prop2: boolean;
prop3: string;
}): Foo;
从关于Overloads的 TypeScript 文档:
JavaScript 本质上是一种非常动态的语言。 单个 JavaScript 函数根据传入参数的形状返回不同类型的对象的情况并不少见。
正如Cenk 的回答,只有当返回类型不同时, send()
的类型才应该使用重载。 否则, send(data: Email | Email[]): foo
对 API 用户来说更合适和方便。 因此,您的包装器拥有这种类型是一个不错的选择。
在这种情况下,为了改进包装器主体代码,我们可以将data
转换为Email[]
以仅使用一个重载并避免明显的代码重复:
const emails = Array.isArray(data) ? data : [data]
const emails = Array.isArray(data) ? data : [data]
或const emails = ([] as Email[]).concat(data)
然后sendGrid.send(emails)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.