I have an enum
enum Action {
action1 = 'action1',
action2 = 'action2'
};
whose values I use as computed property names in an object:
/*
...to be able to use these as values, not just types
*/
const ActionState = {
[Action.action1]: 'actionState1' as const,
[Action.action2]: 'actionState2' as const,
};
I'd like to define a type / an interface whose keys are template literals mapping an Action
to the corresponding ActionState
:
/*
{
actionState1: boolean;
actionState2: boolean;
}
*/
type ActionModelState {
[key in keyof Action as `${typeof ActionState[key]}`]: boolean // all booleans but I need the keys to be restricted
}
// throwing:
// Type 'key' cannot be used to index type '{ action1: "actionState1"; action2: "actionState2"; }'.
with which I'll extend my base type:
type BaseAction = {
id: number;
foo: string;
bar: string;
};
to form:
type EnrichedAction = BaseAction & ActionModelState;
to end up with:
const enrichedAction: EnrichedAction = {
id: 123,
foo: 'foo',
bar: 'bar',
actionState1: true,
actionState2: false,
}
How can I define ActionModelState
when I clearly know the members of Action
as well as ActionState
? The compiler complains that:
Type 'key' cannot be used to index type '{ action1: "actionState1"; action2: "actionState2"; }'
but I figure typeof key === keyof Action
. What am I doing wrong?
CodePudding user response:
You just don't need keyof Action
here at all; the type Action
is already the union of those string values. So you want key in Action
, not key in keyof Action
.
type ActionModelState = {
[key in Action as `${typeof ActionState[key]}`]: boolean
}
CodePudding user response:
It turns out, instead of trying to tame keyof
, I can use a ValueOf
helper -- Playground.
type ValueOf<T> = T[keyof T];
type ActionModelState = {
[key in ValueOf<typeof ActionState>]: boolean;
}
I still wonder whether I can use template literals in some shape or form...