I want to convert a structure type into another. The source structure is an object which possibly contains properties keys splitted by a dot. I want to expand those "logic groups" into sub-objects.
Hence from this:
interface MyInterface {
    'logicGroup.timeout'?: number;
    'logicGroup.serverstring'?: string;
    'logicGroup.timeout2'?: number;
    'logicGroup.networkIdentifier'?: number;
    'logicGroup.clientProfile'?: string;
    'logicGroup.testMode'?: boolean;
    station?: string;
    other?: {
        "otherLG.a1": string;
        "otherLG.a2": number;
        "otherLG.a3": boolean;
        isAvailable: boolean;
    };
}
to this:
interface ExpandedInterface {
    logicGroup: {
        timeout?: number;
        serverstring?: string;
        timeout2?: number;
        networkIdentifier?: number;
        clientProfile?: string;
        testMode?: boolean;
    }
    station?: string;
    other?: {
        otherLG: {
            a1: string;
            a2: number;
            a3: boolean;
        },
        isAvailable: boolean;
    };
}
__
(EDIT) These two structures above are based, of course, on a real Firebase-Remote-Config Typescript transposition that cannot have arbitrary props (no index signatures) or keys collision (we don't expect to have any logicGroup and logicGroup.anotherProperty).
Properties can be optional (logicGroup.timeout?: number) and we can assume that if all the properties in logicGroup are optional, logicGroup itself can be optional.
We do expect that an optional property (logicGroup.timeout?: number) is going to maintain the same type (logicGroup: { timeout?: number }) and not to become mandatory with the possibility to explicitly accept undefined as a value (logicGroup: { timeout: number | undefined }).
We expect all the properties to be objects, strings, numbers, booleans. No arrays, no unions, no intersections.
I've tried sperimenting a bit with Mapped Types, keys renaming, Conditional Types and so on. I came up with this partial solution:
type UnwrapNested<T> = T extends object
    ? {
        [
            K in keyof T as K extends `${infer P}.${string}` ? P : K
        ]: K extends `${string}.${infer C}` ? UnwrapNested<Record<C, T[K]>> : UnwrapNested<T[K]>;
      }
    : T;
Which doesn't output what I want:
type X = UnwrapNested<MyInterface>;
//   ^?    ===> { logicGroup?: { serverString: string | undefined } | { testMode: boolean | undefined } ... }
So there are two issues:
- logicGroup is a distributed union
 - logicGroup properties hold 
| undefinedinstead of being actually optional. 
So I tried to prevent the distribution by clothing K value:
type UnwrapNested<T> = T extends object
    ? {
        [
            K in keyof T as K extends `${infer P}.${string}` ? P : K
        ]: [K] extends [`${string}.${infer C}`] ? UnwrapNested<Record<C, T[K]>> : UnwrapNested<T[K]>;
      }
    : T;
This is the output, but it is still not what I want to get:
type X = UnwrapNested<MyInterface>;
//  ^?    ===> { logicGroup?: { serverString: string | boolean | number | undefined, ... }}
One problem goes away and another raises. So the issues are:
- All the sub properties get as a type a union of all the values available in the same "logic group"
 - All the sub properties hold 
| undefinedinstead of being actually optional. 
I've also tried to play with other optionals in the attempt of filtering the type and so on, but I don't actually know what I am missing.
I also found https://stackoverflow.com/a/50375286/2929433, which actually works on its own, but I wasn't able to integrate it inside my formula.
What I'm not understanding? Thank you very much!