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

Time:09-22

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?

CodePudding user response:

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']);

CodePudding user response:

Slightly different answer that allows you to use Levels as in the OP:

type Level1 = keyof typeof obj;
type Levels<T = Level1> = T extends Level1 ? [T, (typeof obj)[T][number]] : never;

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

This makes use of distributive conditional types, which is why there needs to be an extends on the right of the equal sign rather than as a constraint on T.

  • Related