繁体   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