首页 > 解决方案 > 有没有办法让打字稿推断数组的每个单独索引的类型,而函数中没有类型参数?

问题描述

标题可能令人困惑,我不确定如何正确表达它,但简而言之,我想完成以下任务:

type A<T extends new (...args: any) => any = any> = [T, Required<InstanceType<T>>];

function b<T extends new (...args: any) => any, T2 extends new (...args: any) => any>(...args: [A<T>, A<T2>?]) { };

class C { d?: string; e?: number };

class F { g?: string; h?: number };

b([C, { d: '', e: 2 }], [F, { g: '', h: 3 }]);

但是不必T, T2在函数中包含类型参数b,因为在我的用例中,函数不会为参数定义长度。这可能吗?如果没有,有更好的解决方案吗?

标签: typescript

解决方案


假设您希望b获取任意数量的 type 参数A,这本身就是参数,那么不幸的是没有。这样做可能有一种 hacky 方式,但它肯定不干净,并且可能依赖递归类型来处理强制数组的第二个成员基于第一个成员进行类型检查。

核心问题是 Typescript 不支持更高种类的类型。所以你需要的是可以参数化的东西Array<T>where Tis parameterized over A<K>。这意味着需要一个b看起来像这样的函数

export declare function b<T extends A<K>[]>(...args: T);

whereb是参数化的,T哪个是参数化的K。这是目前在 TypeScript 中无法实现的。

您可以省略参数化K并拥有

export declare function b<T extends A[]>(...args: T);

但是使用上面的 TypeScript 将无法强制执行数组的类型。例如,它将允许b([C, { doesnt_exist: '', e: true }]);您缺少d类中所需的属性C并且e类型错误。

为了在 TypeScript 中正确执行此操作,您需要将此函数的实现拆分为两个不同的函数,每个函数只能对一个类型参数进行参数化。

type A<T extends new (...args: any) => any = any> = [T, Required<InstanceType<T>>];

function makeA<T extends new (...args: any) => any>(a: A<T>) {return a;}

function b<T extends A[]>(...args: T) { };

class C { d?: string; e?: number };

class F { g?: string; h?: number };

class I { j?: string; k?: number };

b(makeA([C, { d: 'hello', e: 4 }]), makeA([F, { g: 'string', h: 5 }]), makeA([I, { j: 'test', k: 6 }]));

所以 nowb是参数 onArray<T>并且makeA是参数 on A<K>。因此,将这两者结合起来,您基本上得到了您正在寻找的更高种类的类型,尽管它不像在 Haskell 中那样实用。

以这种方式使用该b函数更难,但您将在b.


推荐阅读