I feel like this should not be so difficult. Yet, no matter what I try, I can't get it to work. Here's the best I got so far:
// Sample type. I want to make this into 'a' | 'b' | 'x' | 'c' | 'd'
type O = Record<'a', Record<'b' | 'x', Record<'c' | 'd', string | number>>>;
// Explicit way of doing it, with limited depth
type Explicit = keyof O | keyof O[keyof O] | keyof O[keyof O][keyof O[keyof O]];
// What I hoped would work
type ExtractKeys<T> = T extends Record<infer U, any> ?
keyof T | ExtractKeys<T[U]> :
never;
// Or
type ExtractKeys2<T> = T extends Record<string, any> ?
keyof T | ExtractKeys<T[keyof T]> :
never;
// Try it
// TS2589: Type instantiation is excessively deep and possibly infinite.
const tryIt: ExtractKeys<O> = 'a';
// Can assign anything
const tryIt2: ExtractKeys2<O> = 'z';
The error is quite clear, I'm somehow ending up with infinite recursion. Yet I really do not see how? Nor do I find a better way. Any ideas?