简体   繁体   English

如何使用可选参数使 TypeScript 中的 function 过载?

[英]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.出于向后兼容的目的(并保持代码干燥),我不想创建另一个名为savePromisesaveCallback并将其分离出来。 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 实现这一目标?

TL;DR TL;博士

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

see code pan码盘

Explanation解释

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.

相关问题 如何在打字稿中正确重载具有多个参数的函数? - How to overload a function with multiple parameters correctly in typescript? 是否可以通过这种方式为可选参数重载 Typescript 函数? - Is it possible to overload Typescript functions for optional parameters in this way? 如何在 TypeScript 中重载可选 boolean - How to overload optional boolean in TypeScript Typescript function 参数过载 rest - Typescript function overload with rest parameters Typescript function 过载,带可选参数和 rest 参数 - Typescript function overload with optional param and rest params Typescript function 过载,通用可选参数 - Typescript function overload, generic optional parameter React 中的 TypeScript:在接口中使用可选函数参数时,“没有重载匹配此调用” - TypeScript in React: 'No Overload Matches this Call' when using optional function parameters in interface 打字稿:带有可选参数的重载:“重载签名与函数实现不兼容。” - Typescript: Overload with optional paramters: "Overload signature is not compatible with function implementation." 如何将可选的命名参数添加到TypeScript函数参数? - How can I add optional named parameters to a TypeScript function parameter? 我该如何处理Typescript的可选函数参数? - How can I deal with optional function parameters with Typescript?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM