定义动态回调类型的最佳方法是什么



我(在TypeScript中(有一个名为"Instructions"的类,它有一个称为"operate"的静态方法。此方法接受两个特定的参数,以及另外两个可能的参数。第一个参数是"operate"方法应该调用的"回调函数",其余参数与将作为第一个参数传递给回调函数的参数相同。我的问题是,如何定义回调函数的类型。

起初,我想这样实现它:

interface Operand {
// ...
}
interface OperationFunc {
(dstOperand: Operand, srcOperand?: Operand, powerEvaluation?: number): void;
}
class Instructions {
static operate (callback: OperationFunc, dstOperand, srcOperand?, powerEvaluation?) {
callback(dstOperand, srcOperand, powerEvaluation);
}
}

由于几个原因,结果没有成功。主要原因是回调函数不是每次调用中都是相同的函数。但是,这些是不同的函数,每次我都会根据需要传递不同的回调函数。有时它是一个接收单个"操作数"类型参数的函数,有时它是接收两个"操作数"类型参数的功能,有时它也是一个接收三个参数的功能-其中两个是"操作数(Operand("类型,第三个是"数字(number("类型。这三种类型的函数返回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 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);
}

现在有一个函数可以用四种方式调用。因此,它将接受所有这些电话。

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类型的函数接受两个参数、三个参数或任意多个参数。Javascript(和Typescript(总是允许函数接受额外的参数,并将静默地丢弃它们。由于Typescript无法区分一个参数的函数和忽略第二个参数的两个参数的功能,因此它认为(a) => {}在这种情况下实际上是两个参数组成的函数。我不知道有什么方法可以绕过这一点,因为类型检查器实际上是正确的,代码将运行(尽管这可能是程序员的错误(。

我们可以利用重载来描述此函数的可能行为:

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〃;声明";为每个函数声明每个重载,最后一个重载就是所有重载的组合。

然而,当试图调用回调时,我们会收到一个错误:

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不知道被调用的函数应该接收正确的参数,但我们知道如果强制使用重载签名,这是安全的。

对于运行时类型检查,您可以检查args的长度,但可以通过使用@ts-ignore忽略它或将callback的类型更改为更通用的类型(如Function甚至any(来解决此错误。

游乐场

相关内容

最新更新