簡體   English   中英

定義一種動態回調的最佳方式是什么?

[英]What is the best way to define a type of dynamic callback?

我有(在 TypeScript 中)一個名為“Instructions”的 class,它有一個名為“operate”的 static 方法。 此方法接受兩個確定的 arguments,以及另外兩個可能的。 第一個參數是“操作”方法應該調用的“回調函數”,arguments 的 rest 與將傳遞給回調 function 的 arguments 相同,我作為第一個參數獲得了回調函數。 我的問題是,如何定義回調function的類型。

起初,我想這樣實現它:

interface Operand {
  // ...
}

interface OperationFunc {
  (dstOperand: Operand, srcOperand?: Operand, powerEvaluation?: number): void;
}

class Instructions {
  static operate (callback: OperationFunc, dstOperand, srcOperand?, powerEvaluation?) {
    callback(dstOperand, srcOperand, powerEvaluation);
  }
}

由於幾個原因,結果證明是不成功的。 主要原因是每次調用回調function不是同一個function。 但是 - 這些是不同的功能,每次我根據需要傳遞不同的回調 function。 有時它是一個 function 接收單個“操作數”類型參數,有時它是一個 function 接收兩個“操作數”類型 arguments,有時它是一個 function 接收三個 arguments - 其中兩個是“操作數”類型,第三個是“數字”類型。 這三種類型的函數返回 void。

interface Operand {
  // ...
}
type Function1 = (dst: Operand) => void; // The first type of callback functions
type Function2 = (dst: Operand, src: Operand) => void; // The second type of callback functions
type Function3 = (dst: Operand, src: Operand, powerEvaluation: number) => void; // The third type of callback functions

有誰知道如何定義這種回調 function 的類型?

使用generics實用程序類型,您可以定義一個類型,該類型一般應用於您提供的類型 arguments。例如,您可以定義一個 function,它將另一個 function 作為參數,以及該 function 的參數。

function wrapper<
  T extends (...params: any[]) => any
>(func: T, ...params: Parameters<T>): ReturnType<T> {
  return func(...params);
}

function theFunc(x: string, y: number, z: string) {
  return x + " " + y +  " " + z;
}

console.log(wrapper(theFunc, "i would like", 1, "tall glass of milk"));

操場上看到它。

重載簽名會給你正確的想法。

static operate (callback: (a: Operand) => void, dstOperand: Operand);
static operate (callback: (a: Operand, b: Operand) => void, dstOperand: Operand, srcOperand: Operand);
static operate (callback: (a: Operand, b: Operand, c: number) => void, dstOperand: Operand, srcOperand: Operand, powerEvaluation: number);
static operate (callback: (a: Operand, b: Operand, c: number) => void, dstOperand?: Operand, srcOperand?: Operand, powerEvaluation?: number) {
  callback(dstOperand, srcOperand, powerEvaluation);
}

現在有一個function可以通過四種方式調用。 所以它將接受所有這些調用。

Instructions.operate((a) => {}, 0);
Instructions.operate((a, b) => {}, 0, 0);
Instructions.operate((a, b, c) => {}, 0, 0, 0);

但是它會拒絕這個

Instructions.operate((a, b) => {}, 0);

一句警告。 此簽名還將接受以下(可能是錯誤的)調用。

Instructions.operate((a) => {}, 0, 0);

那是因為(a) => {}的類型被推斷為(a: Operand) => void 類型為(a: Operand) => void的 function 完全允許使用兩個 arguments,或三個 arguments,或任意多個 arguments。 Javascript(和 Typescript)總是允許 function 占用額外的 arguments 並默默地丟棄它們。 由於 Typescript 無法區分一個參數的 function 和忽略其第二個參數的兩個 arguments 的 function 之間的區別,因此它認為(a) => {}實際上是 function 中的兩個 884225120046 我不知道有什么方法可以解決這個問題,因為類型檢查器實際上是正確的,代碼將運行(盡管它可能是程序員錯誤)。

我們可以使用重載來描述這個 function 的可能行為:

    static methymethod(callback: Function1, ...args: Parameters<Function1>): void;
    static methymethod(callback: Function2, ...args: Parameters<Function2>): void;
    static methymethod(callback: Function3, ...args: Parameters<Function3>): void;
    static methymethod(callback: Function1 | Function2 | Function3, ...args: Parameters<Function1 | Function2 | Function3>) {

前 3 個“聲明”聲明了每個 function 的每個重載,最后一個只是將它們全部組合在一起。

但是,當嘗試調用回調時,我們收到一個錯誤:

The 'this' context of type 'Function1 | Function2 | Function3' is not assignable to method's 'this' of type '(this: null, dst: Operand) => void'.
  Type 'Function2' is not assignable to type '(this: null, dst: Operand) => void'.(2684)

這是因為 TypeScript 不知道調用的 function 應該接收正確的 arguments,但我們知道如果強制執行重載簽名是安全的。

對於運行時類型檢查,您可以檢查args的長度,但可以通過使用@ts-ignore忽略它或將callback類型更改為更通用的類型(如Function或什至any .

操場

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM