Reputation: 15434
Here is my code. Generally class keeps map of other classes and in a method I want to enforce that given key is accompanied by class instance which is instance of class kept in map at key. In comments you can see where ts shows errors.
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'
Upvotes: 1
Views: 62
Reputation: 249716
To get the instance type from a constructor you can use the predefined InstanceType
conditional type:
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];
}
}
Upvotes: 2