[英]How to overload function in TypeScript with optional parameters?
I have the following code that is partly converted to TypeScript (from JavaScript).我有以下代码部分转换为 TypeScript (来自 JavaScript)。
Basically if a callback
parameter exists, I always want the function itself to return void
.基本上,如果存在
callback
参数,我总是希望 function 本身返回void
。 Otherwise, return type Promise<object>
.否则,返回类型
Promise<object>
。 With an optional parameter ( settings
) before that (so technically the callback
parameter could be passed in as the settings
parameter, which the first few lines of the function handle that use case).在此之前有一个可选参数(
settings
)(因此从技术上讲, callback
参数可以作为settings
参数传入,function 的前几行处理该用例)。
For backwards compatibility purposes (and to keep code DRY), I do not want to create another function called savePromise
or saveCallback
and separate it out.出于向后兼容的目的(并保持代码干燥),我不想创建另一个名为
savePromise
或saveCallback
并将其分离出来。 I'm trying to figure out how to get TypeScript to be smart enough to understand this logic somehow.我试图弄清楚如何让 TypeScript 足够聪明,以某种方式理解这个逻辑。
type CallbackType<T, E> = (response: T | null, error?: E) => void;
class User {
save(data: string, settings?: object, callback?: CallbackType<object, string>): Promise<object> | void {
if (typeof settings === "function") {
callback = settings;
settings = undefined;
}
if (callback) {
setTimeout(() => {
callback({"id": 1, "settings": settings});
}, 1000);
} else {
return new Promise((resolve) => {
setTimeout(() => {
resolve({"id": 1, "settings": settings});
}, 1000);
});
}
}
}
const a = new User().save("Hello World"); // Should be type Promise<object>, should eventually resolve to {"id": 1, "settings": undefined}
const b = new User().save("Hello World", (obj) => {
console.log(obj); // {"id": 1, "settings": undefined}
}); // Should be type void
const c = new User().save("Hello World", {"log": true}); // Should be type Promise<object>, should eventually resolve to {"id": 1, "settings": {"log": true}}
const d = new User().save("Hello World", {"log": true}, (obj) => {
console.log(obj); // {"id": 1, "settings": {"log": true}}
}); // Should be type void
I'm pretty sure the type file I'm aiming for would be something along the lines of the following.我很确定我想要的类型文件将类似于以下内容。 Not sure I'm accurate here tho.
不确定我在这里是否准确。
save(data: string, settings?: object): Promise<object>;
save(data: string, callback: CallbackType<object, string>): void;
save(data: string, settings: object, callback: CallbackType<object, string>): void;
It seems like the callback
parameter being passed in as the settings
parameter use case can be handled by doing something like:似乎可以通过执行以下操作来处理作为
settings
参数用例传入的callback
参数:
save(data: string, settings?: object | CallbackType<object, string>, callback?: CallbackType<object, string>): Promise<object> | void
But that is super messy, and from my experience it doesn't seem like TypeScript is smart enough to realize that settings
will always be an optional object after those first 4 lines of code in the function.但这太混乱了,根据我的经验,TypeScript 似乎不够聪明,无法意识到在 ZC1C425268E68A385D1AB5074FC17 中的前 4 行代码之后
settings
将始终是可选的 object Which means when calling callback
you have to type cast it, which again, feels really messy.这意味着在调用
callback
时,您必须输入强制类型转换,这再次让人感觉非常混乱。
How can I achieve this with TypeScript?如何使用 TypeScript 实现这一目标?
Here's the solution (with some refactoring):这是解决方案(进行了一些重构):
type CallbackType<T, E> = (response: T | null, error?: E) => void;
interface ISettings {
log?: boolean;
}
interface ISaveResult {
id: number;
settings: ISettings | undefined;
}
class User {
save(data: string): Promise<ISaveResult>;
save(data: string, settings: ISettings): Promise<ISaveResult>;
save(data: string, callback: CallbackType<ISaveResult, string>): void;
save(data: string, settings: ISettings, callback: CallbackType<ISaveResult, string>): void;
save(data: string, settings?: ISettings | CallbackType<ISaveResult, string>, callback?: CallbackType<ISaveResult, string>): Promise<ISaveResult> | void {
if (typeof settings !== "object" && typeof settings !== "undefined") {
callback = settings;
settings = undefined;
}
const localSettings = settings; // required for closure compatibility
if (callback) {
const localCallback = callback; // required for closure compatibility
setTimeout(() => {
localCallback({ id: 1, "settings": localSettings });
}, 1000);
} else {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ id: 1, "settings": localSettings });
}, 1000);
});
}
}
}
const a = new User().save("Hello World"); // User.save(data: string): Promise<ISaveResult>
const b = new User().save("Hello World", obj => {
console.log(obj); // obj: ISaveResult | null
}); // User.save(data: string, callback: CallbackType<ISaveResult, string>): void
const c = new User().save("Hello World", { "log": true }); // User.save(data: string, settings: ISettings): Promise<ISaveResult>
const d = new User().save("Hello World", { "log": true }, (obj) => {
console.log(obj); // obj: ISaveResult | null
}); // User.save(data: string, settings: ISettings, callback: CallbackType<ISaveResult, string>): void
a Function
is an Object
as well, so TypeScript was not able to implicitly distinguish between the two. Function
也是Object
,因此 TypeScript 无法隐式区分两者。 By creating a specific ISettings
interface, you allow TypeScript to distinguish between a settings object and a callback function.通过创建特定的
ISettings
接口,您允许 TypeScript 区分设置 object 和回调 function。
The easiest way to see that is look at the errors TypeScript puts out and the types of the variables as the code flow progresses, eg ( your code ):最简单的查看方法是查看 TypeScript 输出的错误以及代码流进行时的变量类型,例如( 您的代码):
When hovering over settings
in if
condition:在
if
条件下将鼠标悬停在settings
上时:
When hovering over settings
inside if
block:将鼠标悬停在
if
块内的settings
上时:
callback
assignment error: callback
分配错误:
Type 'Function' is not assignable to type 'CallbackType'.
类型“Function”不可分配给类型“CallbackType”。 Type 'Function' provides no match for the signature '(response: object | null, error?: string | undefined): void'.(2322)
类型“函数”不匹配签名“(响应:object | null,错误?:字符串|未定义):无效”。(2322)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.