如何强制参数成为某个对象的属性的构造函数/类的实例?

时间:2019-02-15 13:25:30

标签: typescript

这是我的代码。 通常,类保留其他类的映射,并且在一种我想强制执行的方法中,给定的键要伴随有类实例,该类实例是保存在map处的类的实例。在注释中,您可以看到ts显示错误的地方。

abstract class AbstractSerializable {
  public abstract run(): void;
}

interface ISerializable {
  serialize: (cls: AbstractSerializable) => any;
  deserialize: (json: any) => AbstractSerializable;
}

type ClassMapItem = (new (...args: any[]) => AbstractSerializable) & ISerializable;

interface ClassMap {
  [key: string]: ClassMapItem;
}

abstract class AbstractClassManager<T extends ClassMap> {
  public readonly classMap: T;

  public serializeInstance<K extends keyof T>(
    key: K & string,
    instance: T[K], // <- I want to enforce "instance" to be instance of this.classMap[key]
  ): any {
    const Constructor = this.getClass(key);
    const json = Constructor.serialize(instance); // ERROR: Property 'run' is missing in type 'ClassMapItem'
    return json;
  }

  public getClass<K extends keyof T>(key: K & string) {
    return this.classMap[key];
  }
}

class SomeClass extends AbstractSerializable {
  public static serialize(c: SomeClass) {
    return {};
  }
  public static deserialize(json: any) {
    return new SomeClass();
  }

  public run() {
    return;
  }
}

const classMap: ClassMap = {
  someClass: SomeClass,
};

class ClassManager extends AbstractClassManager<typeof classMap> {

}

const manager = new ClassManager();
manager.serializeInstance('someClass', new SomeClass()); // ERROR: Type 'SomeClass' provides no match for the signature 'new (...args: any[]): AbstractSerializable'

1 个答案:

答案 0 :(得分:2)

要从构造函数中获取实例类型,可以使用预定义的InstanceType条件类型:

abstract class AbstractClassManager<T extends ClassMap> {
    public readonly classMap!: T;

    public serializeInstance<K extends keyof T>(
        key: K & string,
        instance: InstanceType<T[K]>, // The type of the instance T[K] returns
    ): any {
        const Constructor = this.getClass(key);
        const json = Constructor.serialize(instance);
        return json;
    }

    public getClass<K extends keyof T>(key: K) {
        return this.classMap[key];
    }
}