Skip to content

Instantly share code, notes, and snippets.

@webstrand
Last active October 25, 2021 17:59
Show Gist options
  • Select an option

  • Save webstrand/01d38eeecc4a04fe2d96ee219cdc956c to your computer and use it in GitHub Desktop.

Select an option

Save webstrand/01d38eeecc4a04fe2d96ee219cdc956c to your computer and use it in GitHub Desktop.
Flatten or unflatten object types `{ "a.b.c": 1 }` to `{ a: { b: { c: 1 } } }`
type Expand<T> = T extends T ? { [P in keyof T]: T[P] } : never;
type UnionToIntersection<U> = (U extends U ? ((x: U) => any) : never) extends (x: infer I) => any ? I : never;
type Flatten<T, Z extends string = ""> = T extends object
? Expand<UnionToIntersection<{
[P in keyof T]: P extends string | number
? T[P] extends object
? Flatten<T[P], `${Z}${P}.`>
: { [Q in `${Z}${P}`]: T[P] }
: never
}[keyof T & (T extends readonly unknown[] ? number : unknown)]>>
: T;
const DeepObject = {
a: 1,
b: {
c: 2,
d: { e: 3 }
},
e: [1,2,3] as number[],
f: [1,2,3]
} as const;
type e = Flatten<typeof DeepObject>;
type PrefixKeyof<T extends { [key: string]: unknown }> = {
[P in keyof T]: P extends `${infer Q}.${string}` ? Q : never;
}[keyof T];
type Unflatten<T extends { [key: string]: unknown }> = Expand<UnionToIntersection<
| UnflattenDirect<T>
| UnflattenIndirect<T, PrefixKeyof<T>>
>>;
type UnflattenDirect<T extends { [key: string]: unknown }> = {
[P in keyof T]: P extends `${string}.${string}`
? never
: { [Q in P]: T[P] }
}[keyof T];
type UnflattenIndirect<T extends { [key: string]: unknown }, Z extends string> = Z extends Z
? {
[P in Z]: Expand<UnionToIntersection<{
[P in keyof T]: P extends `${Z}.${infer Affix}`
? Unflatten<{ [Q in Affix]: T[P] }>
: never
}[keyof T]>>
}
: never;
type n = Unflatten<e>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment