UjinT34
UjinT34

Reputation: 4987

How to generate type from list of nested keys?

I have data structure similar to:

const Data = {
    key1: {
        key1a: '1a',
        key1b: '1b',
    },
    key2: {
        key2a: '2a',
        key2b: '2b',
    },
    keyN: {
        keyNa: 'Na',
        keyNb: 'Nb',
    },
}

And I want to generate a type for the list of all subkeys like this:

type DataSubkeysV1 = 'key1a' | 'key1b' | 'key2a' | 'key2b' | 'keyNa' | 'keyNb';
type DataSubkeysV2 = keyof typeof Data['key1'] | keyof typeof Data['key2'] | keyof typeof Data['keyN'];

How to write a type definition for any number of top-level keys?

I've tried a generic type:

type DataSubkeysV3<K extends keyof typeof Data> = keyof typeof Data[K]

But it requires an argument. And I want a type that can be used like DataSubkeysV1.

Upvotes: 0

Views: 78

Answers (1)

Lesiak
Lesiak

Reputation: 25966

type UnionKeys<T> = T extends any ? keyof T : never
type FirstLevelValues<T> = T[keyof T]
type SecondLevelKeys<T> = UnionKeys<FirstLevelValues<T>>
type MyKeys = SecondLevelKeys<typeof Data>
// type MyKeys = "key1a" | "key1b" | "key2a" | "key2b" | "keyNa" | "keyNb"

See Checking for union type for the rationale of UnionKeys

we must first get a union of all the keys from all union constituents. To do this we must use the distributive behavior of conditional types. Using this behavior we can build a type that extracts extracts the keys of each union constituent and creates a union of all. To trigger the distributive behavior we can use an always true condition ( T extends T, T extends unknown or, less ideal T extends any).

Upvotes: 1

Related Questions