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;
// }