Home > Mobile >  How to make a 1:1 type map of an object literal with a new type of value as a function return implic
How to make a 1:1 type map of an object literal with a new type of value as a function return implic

Time:09-14

Currently I'm able to get a union of the key and values of each object literal passed into a function.

e.g.

interface StaticClass<T = any> {
  new (...args: any[]): T
}
type RecordOfStaticClasses = Record<string, StaticClass>;
type RecordOfInstances<T extends RecordOfStaticClasses> = Record<keyof T, InstanceType<T[keyof T]>>;

const transformObjLiteral = <T extends RecordOfStaticClasses>(input: T): RecordOfInstances<T> => {
  return Object.fromEntries(Object.entries(input).map(([key, value]) => [key, new value])) as RecordOfInstances<T>;
}

// Transformation
class Cat {
  asleep: boolean;
}
class Zebra {
  hoofLength: number;
}
transformObjLiteral({ myCat: Cat }).myCat.asleep // works if only 1 key is added
transformObjLiteral({ myCat: Cat, myZebra: Zebra }).myCat.asleep // Error: Property 'asleep' does not exist on type 'Cat | Zebra'!

As can be seen from above, it works well when only a object literal with 1 key is passed. However when adding two keys it cant get specific due to the possibility of a Union type. I know I can use Generics (e.g. transformObjLiteral<{ myCat: Cat }>({ myCat: Cat })) but I hope to accomplish this implicitly based on the argument by itself. Is this posible?

CodePudding user response:

Instead of using a Record, use a mapped type directly to keep the association between individual keys K and their InstanceType<T[K]>.

type RecordOfInstances<T extends RecordOfStaticClasses> = {
  [K in keyof T]: InstanceType<T[K]>
}

Playground

  • Related