Home > Net >  Create union of interface values based on keys of another type
Create union of interface values based on keys of another type

Time:11-02

I have an interface with keys as enums and further interfaces as values.

enum Enum {
  Val1, Val2, Val3
}
interface MyInterface {
  [Enum.Val1]: { bookingId: string }
  [Enum.Val2]: { videoId: string }
  [Enum.Val3]: { userId: string }
}

With them I have an associated model:

const EVENT_TASK_MODEL = {
  A: {
    a: [Enum.Val1, Enum.Val2],
  },
  B: {
    c: [Enum.Val2, Enum.Val3]
  }
} as const

Based on the above model, I want to create a union that combines the values for each key of MyInterface based on the provided keys. Something like below:

CombinedModel<"A", "a"> // { bookingId: string } | { videoId: string }

Explanation:

EVENT_TASK_MODEL["A"]["a"] = [Enum.Val1, Enum.Val2]
Look up values in MyInterface: MyInterface[Enum.Val1] and MyInterface[Enum.Val2]
Their values are: { bookingId: string } and { videoId }
Create union: { bookingId: string } | { videoId: string }

CodePudding user response:

We need to create a generic type with two generic parameters K1 and K2. They are constrained to be a valid path in typeof EVENT_TASK_MODEL.

type CombinedModel<
  K1 extends keyof typeof EVENT_TASK_MODEL,
  K2 extends keyof typeof EVENT_TASK_MODEL[K1]
> = 
typeof EVENT_TASK_MODEL[K1][K2] extends infer U extends readonly (keyof MyInterface)[]
  ? MyInterface[U[number]]
  : never

We index EVENT_TASK_MODEL with both K1 and K2 and store the result in U. By adding this extra extends readonly (keyof MyInterface)[], we remind TypeScript what the shape of U should be. At last, we create a union of the tuple stored in U by indexing it with number and use the union to index MyInterface.

type T0 = CombinedModel<"A", "a">
// type T0 = {
//     bookingId: string;
// } | {
//     videoId: string;
// }


type T1 = CombinedModel<"B", "c">
// type T1 = {
//     videoId: string;
// } | {
//     userId: string;
// }

Playground

  • Related