class ClassZ { private a?: 1; } class ClassX { private a?: 1; } class ClassY { private a?: 1; } class ClassW { private a?: 1; } class ClassA { private a?: 1; } class ClassZ1 extends ClassZ { private b?: 1; } class ClassZ2 extends ClassZ { private b?: 1; } class ClassZ3 extends ClassZ { private b?: 1; } class A {} class B {} interface ClassConstruct { new ( prop1: ClassZ, prop2: any, ): A } type ClassConstructor = { class: ClassConstruct otherClasses: { new (): B }[] } enum numericEnum1 { A = 1, B = 2 } enum numericEnum2 { C = 1, D = 2, } enum stringEnum2 { A = 'A', B = 'B', C = 'C', } numericEnum1[numericEnum1.A]//? stringEnum2[stringEnum2.A]//? type enums = keyof typeof numericEnum1 | keyof typeof numericEnum2 | keyof typeof stringEnum2 type stringEnum = { [K in enums & string]: K } function convertEnumsToStringEnum(enums: any[]) { return enums.map((item) => { return Object.fromEntries( Object.values(item) .filter(value => typeof value === 'string') .map(value => [value, value]) ) as stringEnum }).reduce((acc, curr) => { return { ...acc, ...curr } }) } // export function convertEnumToStringEnumObject(enumLike: T) { // type stringEnum = { [K in T & string]: K } // return Object.values(enumLike) // .filter((value) => typeof value === 'string') // .map((value) => [value, value]) // .reduce( // (acc, [key, value]) => Object.assign(acc, { [key]: value }), // {} // ) as stringEnum // } const stringEnum = convertEnumsToStringEnum([numericEnum1, numericEnum2, stringEnum2]) as stringEnum//? // const stringEnum = Object.fromEntries( // Object.values(numericEnum2) // .filter(value => typeof value === 'string') // .map(value => [value, value]) // ) as stringEnum type ObjectMapConstraint = Record>; function createObjectMap(obj: T): T { return obj; } const objectMap = createObjectMap({ parent1: { [stringEnum[stringEnum.A]]: { class: ClassA, otherClasses: [ClassZ1, ClassZ2, ClassZ3] }, [stringEnum[stringEnum.D]]: { class: ClassX, otherClasses: [ClassZ1, ClassZ2, ClassZ3] }, }, parent2: { [stringEnum2[stringEnum2.A]]: { class: ClassX, otherClasses: [ClassZ1, ClassZ2, ClassZ3] }, [stringEnum2[stringEnum2.C]]: { class: ClassY, otherClasses: [ClassZ1, ClassZ2, ClassZ3] } }, parent3: { someChild: { class: ClassW, otherClasses: [ClassZ1, ClassZ2, ClassZ3] } } }) type ObjectMap = typeof objectMap; class factory { static create( parent: K, child: `${keyof ObjectMap[K] & string}` ): any[] { const objMap: ObjectMapConstraint = objectMap const MyClass = objMap[parent][child].class return objMap[parent][child].otherClasses.map((other) => { return new MyClass(new other(), 123) }) } } factory.create("parent1", "D") factory.create("parent2", "A") factory.create("parent1", numericEnum1.B) // error, as expected factory.create("parent3", "someChild")