object keys as type and array of the sub-object as type in typescript

I am trying to use an object and its items as type.

In a code

const obj = {
    a: [
        'hi',
        'hello'
    ] as const,
    b: [
        'see you',
        'good bye'
    ] as const
}

type Level1 = keyof typeof obj;
type Level2 = typeof obj[Level1][number];
type Levels = [Level1, Level2];

const a: Levels = ['a', 'hi']

What I want is that Level2 becomes ‘hi’|’hello’ when Level1 is ‘a’ and ‘see you’|’good bye’ when Level1 is ‘b’. However, Level2 becomes ‘hi’|’hello’|’see you’|’good bye’, whatever Level1 is.
Thus

const a: Levels = ['a', 'hi']; // it should work
const b: Levels = ['a', 'see you'] // it shouldn't work because a does not have 'see you'.

How should Level2 be defined to perform?

>Solution :

Make the Levels type generic so that it can narrow down which second item in the tuple is permitted, given the first item.

type Obj = typeof obj;
type Levels<T extends keyof Obj> = [T, Obj[T][number]];
const a: Levels<'a'> = ['a', 'hi']

Less repetitively, use a function to verify the type so you don’t have to type 'a' twice.

type Obj = typeof obj;
const getA = <T extends keyof Obj>(arr: [T, Obj[T][number]]) => arr;
const a = getA(['a', 'hi']);

Leave a Reply