Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Is it possible to split object into a union of its properties?

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?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel


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.

>Solution :

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

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading