Reputation: 377
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
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