Leonor
Leonor

Reputation: 377

How can I get an index type from the keys of a typed object?

I have used the keyof operator before to get the keys of an object but I'm stuck on this simple code.

interface Definition { name: string; visible: boolean; itemIds: number[]; }

const Definitions: { [key: string]: Definition } =
{
    line1: { name: 'line 1', visible: true, itemIds: [1, 2, 3] },
    line2: { name: 'line 2', visible: true, itemIds: [4, 5, 6, 7] },
    next_line: { name: 'next', visible: false, itemIds: [] },
    // more items here...
    prod: { name: 'production', visible: true, itemIds: [718, 719] },
};

type DefKeys = keyof typeof Definitions; // Wrong!

What I would like to get is

DefKeys = 'line1' | 'line2' | 'next_line' | 'prod'

But I'm actually getting

DefKeys = string | number

If I remove the type constraint on my object I get what I'm expecting, but I lose the type safety.

const Definitions = // No type here
{
    line1: { name: 'line 1', visible: true, itemIds: [1, 2, 3] },
    line2: { name: 'line 2', visible: true, itemIds: [4, 5, 6, 7] },
    next_line: { name: 'next', visible: false, itemIds: [] },
    // more items here...
    prod: { name: 'production', visible: true, itemIds: [718, 719] },
};

type DefKeys = keyof typeof Definitions; // correct

How can I keep my type on the definition of my object and get an index type from it?

Upvotes: 1

Views: 59

Answers (1)

Aleksey L.
Aleksey L.

Reputation: 37928

You can wrap definitions creation into function call with generic type parameter and define the constraint on the parameter. This way original object type will be preserved:

function getDefinitions<T extends { [key: string]: Definition }>(definitions: T): T {
    return definitions;
}

const Definitions = getDefinitions({
    line1: { name: 'line 1', visible: true, itemIds: [1, 2, 3] },
    line2: { name: 'line 2', visible: true, itemIds: [4, 5, 6, 7] },
    next_line: { name: 'next', visible: false, itemIds: [] },
    // more items here...
    prod: { name: 'production', visible: true, itemIds: [718, 719] },
});

type DefKeys = keyof typeof Definitions; // "line1" | "line2" | "next_line" | "prod"

Upvotes: 2

Related Questions