3

I have object https://www.typescriptlang.org/play:

const obj =
{
    list: ["Example1", "Example2"],
    settings: {isEnabled: true, version: "v1.1"},
    extra: {1: "", 2: "", 3: ""}
}

I want to split obj into a union of its properties: {list: ...} | {settings: ...} | {extra: ...}:

type obj = typeof obj;
type expected = {list: Array<string>} | {settings: {isEnabled: boolean, version: string}} | {extra: {1: string, 2: string, 3: string}};

Is this possible?


My attempts:

// this doesn't work, it's my attempt, how to introduce recursion here?
type Split<T extends {}> = [keyof T] extends [c: infer C1, ...rest: infer C2] ? C1 | C2 : "1"; 
type Split1<T extends {}> = [keyof T] extends (infer C1 | infer C2) ? {[C1]: any} | {[C2]: any} : "1"; 
type result = Split<obj>;
type result1 = Split1<obj>;

I know that somehow I need to introduce recursion with destructuring assignment, but can't figure out how.

pax
  • 17
  • 4
Sonny D
  • 897
  • 9
  • 29

1 Answers1

1

We will need to use a mapped type to generate a type which will have the following structure:

// Initial
{
 x: string
 y: number
}

// Result
{
 x: {x: string}
 y: {y: number}
}

After that, we can just take all values, which will generate a union that you want:

type Split<T extends object> = {
  [K in keyof T]: { [P in K]: T[P] };
};

Testing:

// type Result = {
//     list: {
//         list: string[];
//     };
//     settings: {
//         settings: {
//             isEnabled: boolean;
//             version: string;
//         };
//     };
//     extra: {
//         extra: {
//             1: string;
//             2: string;
//             3: string;
//         };
//     };
// }
type Result = Split<typeof obj>;

Looks good, now by using ValueOf described in here, we will get all values:

type ValueOf<T> = T[keyof T];

type Split<T extends object> = ValueOf<{
  [K in keyof T]: { [P in K]: T[P] };
}>;

Testing:

// type Result = {
//   list: string[];
// } | {
//   settings: {
//       isEnabled: boolean;
//       version: string;
//   };
// } | {
//   extra: {
//       1: string;
//       2: string;
//       3: string;
//   };
// }
type Result = Split<typeof obj>;

playground

wonderflame
  • 6,759
  • 1
  • 1
  • 17