如何使用 TypeScript "keyof" 创建通用 API 接口的接口?

How to use TypeScript "keyof" to create interface to generic API interface?

我在使用 TypeScript 的类型系统建模通用接口以从 Lua 调用 TypeScript 时遇到问题。为此,开发人员必须定义一个 TypeScript 接口,定义 Lua 可以调用的 TypeScript 方法。细节在这里并不重要,因为下面的简单示例说明了我的困惑。

正如您从上面的代码中看到的,我有“ApiInterface”,它定义了开发人员可能希望从 Lua 调用的任意方法。所有这些方法都采用第一个参数,即 object(类似于 'this'),其余参数可以是开发人员需要从 Lua 传递到 TypeScript 方法的任何参数。实际上,这些剩余参数支持的唯一类型是原始类型,如数字、字符串、布尔值、空值。在上面的示例代码中,我定义了 3 个这样的 API 方法,但是开发人员可以定义他们想要的任何方法。这个 Lua-to-TypeScript 模块的重点是通用的,而不是绑定到“ApiInterface”的任何特定定义。

运行time 最终将 Lua-to-TypeScript 方法调用打包成一个 object 类型的 ApiCall,你可以看到它是用方法名称字段定义的, JavaScript object 用于“this”,以及剩余的任意参数。

为了说明我的困惑,我展示了一个 KeyofDemo 来说明我遇到的 TypeScript 错误。 KeyofDemo class 中有一个“运行” 方法,它想要获取 ApiCall object 并调用相应的 TypeScript/JavaScript 函数。

可以看到两种情况下实际调用方法下的red-squiggly。一种情况是没有其他参数(除了必需的“this”参数之外),另一种情况是 ApiCall.args 实际上填充了一组参数以从 Lua 传递给 TypeScript。

第一个 red-squiggly 案例的错误消息是:A spread argument must either have a tuple type or be passed to a rest parameter

第二个 red-squiggly 案例的错误消息是:Expected 3 arguments but got 1.

这些错误消息对我来说都没有任何意义。如果我尝试编译上面的 TypeScript 代码,编译器会报告类似的错误。

如何让 TypeScript 的类型系统最好地模拟我所描述的行为?现在,我通过将第 23 行和第 25 行的大小写“this.api”更改为“any”解决了这个问题,这关闭了 TypeScript 编译器。但我想知道如何正确建模这个问题。

第一个错误是因为 Javascript/Typescript 不支持在参数中使用扩展运算符,除非您的函数配置为这样做。

您必须将函数配置为接受可变参数。

interface ApiInterface {
    apiMethod0(thisObj: Object, ...args: any[]): void
    apiMethod1(thisObj: Object, ...args: [string]): void
    apiMethod2(thisObj: Object, ...args: [number, boolean]): void
}

See this code in playground

第二个错误是因为所有方法都必须具有相同的“形状”,或者具有相同的参数数量。在这种情况下,我们用相同的石头杀死了两只鸟。