在命名空间类的实例上进行类型解析

时间:2019-08-18 09:08:23

标签: typescript

让我们说一下在代码中我们有名称空间的地方,该名称空间是由export-import例程创建的。

namespace ClassCollection {
  export class Test1 {
    public Method1() { return 1; }
  }
  export class Test2 {
    public Method2() { return 2; }
  }
}

在主模块中的其他地方,我们要定义一个变量,该变量代表那些类的实例的字典。它的意思是通过循环遍历名称空间元素来自动完成,但是最后看起来像这样:

const collection = {
  Test1: new ClassCollection.Test1,
  Test2: new ClassCollection.Test2,
}

// to be accessible like this
collection.Test1.Method1();
collection.Test2.Method2(); 

每个类都可以轻松解决,就像这样:

const Test1: InstanceType<(typeof ClassCollection)["Test1"]> 
  = new ClassCollection.Test1;
const Test2: InstanceType<(typeof ClassCollection)["Test2"]> 
  = new ClassCollection.Test2;

Test1.Method1();
Test2.Method2();

但是如何为此进行通用类型解析?我最好的尝试是:

type TypeResolution<T> = {
  [C in keyof T]: InstanceType<T[C]>;
};

/** won't work because of: 
 * Type 'T[C]' does not satisfy the constraint 'new (...args: any) => any'.
 */
const collection: TypeResolution<typeof ClassCollection> = {
  Test1: new ClassCollection.Test1,
  Test2: new ClassCollection.Test2,
};

1 个答案:

答案 0 :(得分:1)

该错误告诉您T[C]无法通过验证代表构造函数,因此TypeScript无法保证可以推断ClassCollection命名空间中所有属性的实例类型。

通过在通用类型参数T上包含类型约束,可以告诉TypeScript实际上所有属性实际上都代表构造函数:

type TypeResolution<T extends Record<string, { new (...args: any[]): any }>> = {
  [C in keyof T]: InstanceType<T[C]>;
};

现在,您可以为编译器提供足够的信息来计算实例类型and it all works correctly