I have a complex Flattened type that gives me a result that is right for me.
However the resulting type has a lot of duplicate intersections when, in the input record:
- A key is isolated (in the example the key
d) - The corresponding value is a union
type Primitive = number | string | boolean | Date;
export type UnionToIntersection<U> =
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(U extends any ? (k: U) => void : never) extends (k: infer I) => void
? I
: never;
export type Flattened<T, Sep extends string> = T extends
| Primitive
| unknown[]
| Record<string, Primitive | unknown[]>
? T
: T extends Record<string, unknown>
? UnionToIntersection<
{
[K in keyof T & string]: Flattened<T[K], Sep> extends infer Flat
? Flat extends Primitive | unknown[]
? { [P in K]: T[P] }
: Flat extends Record<string, unknown>
? {
[KFlat in keyof Flat &
string as `${K}${Sep}${KFlat}`]: Flat[KFlat];
}
: Flat extends unknown
? { [KFlat in K]: Flat }
: never
: never;
}[keyof T & string]
>
: T extends unknown
? T
: never;
type ComplexA = "complexA1" | "complexA2";
type ComplexB = "complexB1" | "complexB2" | "complexB3";
/**
* Expected type:
* {
* a_b: ComplexA;
* } & {
* c_d: ComplexB;
* } & {
* d: ComplexB;
* }
*
*
* Actual type:
* {
* a_b: ComplexA;
* } & {
* c_d: ComplexB;
* } & {
* d: ComplexB;
* } & {
* d: ComplexB;
* } & {
* d: ComplexB;
* }
*/
Flattened<
{
a: { b: ComplexA };
c: { d: ComplexB };
d: ComplexB;
}, '_'
>
Here's a link to a playground that also contains an implementation for a flatten function.