Most TypeScript factory patterns I've encountered rely on a named mapping between a name and the Class type.
A basic implementation example:
const myMap = {
classOne: ExampleClass,
classTwo: AnotherClass
}
(k: string) => { return new myMap[k] }
I wanted to elevate this mapping concept - as my classes follow the structure of ExampleClass implementing iGenericInterface<T>
However, I'm struggling to specify that Record Value types should be restricted to those implementing the iGenericInterface<T>. The problematic area in the following example is marked with ***
export interface iGenericInterface<K> {
process(input: K): void
}
class ExampleClass implements iGenericInterface<string> {
process(input: string): void {
console.log(input);
}
}
class AnotherClass implements iGenericInterface<number> {
process(input: number): void {
console.log(input);
}
}
class UnsupportedClass {
otherMethod(input: boolean): void {
console.log(input);
}
}
enum instantiableClassesEnum { class1, class2, class3 };
type enumValues = keyof typeof instantiableClassesEnum;
type logicStore<T> = Record<enumValues, ***iGenericInterface<T>***>
const classMap: logicStore<any> = {
class1: ExampleClass,
class2: AnotherClass,
class3: UnsupportedClass,
};
I would anticipate an error for the UnsupportedClass, but desire acceptance by the compiler for the others.
If I change ExampleClass
to an instance like class1: new ExampleClass
, the compiler is content. However, I then face uncertainty regarding how to utilize the mapping in the factory method - return new myMap[k]
EDIT - (@Adriaan This is NOT an answer, just a clarification of the end goal) Ability to generate classes based on Enumeration input - utilizing the mapped structure above.
class LogicFactory {
static createLogic<T>(logicClass: enumValues):
iGenericInterface<T> {
return new classMap[logicClass]();
}
}