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.
>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>;