Consider this object:
export const cypher = {
  Foo: {
    get Bar() {
      return 'Foo_Bar';
    },
    get Baz() {
      return 'Foo_Baz';
    },
  },
  get Qux() {
    return 'Qux';
  },
  Lan: {
    Rok: {
      get Saz() {
        return 'Lan_Rok_Saz';
      },
    },
  },
};
You can see the pattern: this is a "tree" where each leaf would return a string of the concatanated names of its entire branch, i.e.
console.log(cypher.Lan.Rok.Saz) // Lan_Rok_Saz
This manual object is strictly typed, so I get intellisense nicely. I would like to now create some constructor, that accepts an object of a type such as:
interface Entries {
  [key: string]: (string | Entries)[];
}
And returns an object with the structure as the above cypher, such that TS would be able to intellisense.
The internal implementation isn't necesarrily important, but the usage of X.Y.Z is definitely a priority.
So far I've tried a recursive function that defines properties based on values:
interface Entries {
  [key: string]: (string | Entries)[];
}
const mockEntries: (string | Entries)[] = ['Gat', 'Bay', {
  Foo: ['Bar', 'Baz', { Cal: ['Car'] }],
}];
function buildCypherFromEntries(entries: (string | Entries)[], parentName: string, cypher: Record<string, any> = {}) {
  entries.forEach(entry => {
    if (typeof entry === 'string') {
      Object.defineProperty(cypher, entry, {
        get() { return (parentName ? `${parentName}_${entry}` : entry); },
      });
    } else {
      Object.entries(entry).forEach(([key, furtherEntries]) => {
        cypher[key] = {};
        const furtherParentName = parentName ? `${parentName}_${key}` : key;
        buildCypherFromEntries(furtherEntries, furtherParentName, cypher[key]);
      })    
    }
  })
  return cypher;
}
const c = buildCypherFromEntries(mockEntries, '');
console.log(c.Gat) // Gat
console.log(c.Bay) // Bay
console.log(c.Foo.Bar); // Foo_Bar
console.log(c.Foo.Cal.Car) // Foo_Cal_Car
This works, but does not give any intellisense. It's also not perfect as it does not support top-level leaves that turn into getters. I also tried doing this in class form but again the typing confounds me.