从模块名称列表中推断函数参数类型

时间:2020-08-08 02:57:53

标签: typescript

我有很多旧的.js文件,目前无法迁移到.ts文件。我正在添加.d.ts文件来添加类型,但是使用类型是一个问题,因为文件通过requireJs相互导入,如下所示:

define(['moduleA', 'moduleB'], function(moduleA, moduleB) {
    // ...
});

在这种情况下,我希望正确键入函数参数moduleAmoduleB。由于模块名称('moduleA', 'moduleB'是在运行时配置文件中自定义的,因此TypeScript真的无法帮助连接点。

所以我有一个想法,就是要扩展define的类型,以便它期望从第一个参数开始的模块名称列表,将它们映射到在映射接口中定义的模块类型,然后键入该函数第二个参数的参数是该模块类型的列表。

我得到了概念工作的基本证明:

/**
 * This interface is used to map module names to their types.
 */
export interface RequireJsModules {
    foo: boolean;
    bar: string;
}

export type RequireJsModulify<T extends string[]> = {
    [P in keyof T]: T[P] extends keyof RequireJsModules
        ? RequireJsModules[T[P]]
        : unknown
};

// This line is for testing `RequireJsModulify`.
type Foo = RequireJsModulify<['foo', 'bar', 'wut']>;

此屏幕截图显示RequireJsModulify正在工作。 Foo的类型是基于模块名称的元组的正确模块类型的元组。 Screenshot of type inference of type Foo is [number, string, unknown].

我受困的是define函数签名:

declare global {
    export function define<T extends string[], U extends RequireJsModulify<T>>(
        deps: T,
        moduleFactory: ((...args: U) => any)
    ): void;
}

想法是moduleFactory的参数必须是基于类型参数T的映射模块类型,类型参数RequireJsModules是任意字符串列表。如果字符串是映射接口unknown的键,则相应的函数参数应具有该模块类型,否则参数应具有describe('requirejs type', () => { it('should call the module factory with the correct types corresponding to the dependencies', () => { // There should be no type errors below. define(['foo', 'bar', 'wut'], function(foo, bar, wut) { const fooExpected: boolean = foo; const barExpected: string = bar; const wutExpected: unknown = wut; console.log({ fooExpected, barExpected }); }); }); }); 类型。

我有这个测试用例:

define

如果foo的类型按照我想要的方式工作,则第一个参数boolean的类型应为bar,第二个参数string的类型应为{{1 }},而第三个应该是unknown

但是目前他们都是unknown

因此:

Screenshot of type error about assigning unknown type to boolean type.

我正在使用TypeScript 3.9.7。

有什么想法为什么不起作用?

0 个答案:

没有答案