Home > Enterprise >  Object literals combining enums and computed property names
Object literals combining enums and computed property names

Time:09-22

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?

Playground link

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
}

Playground Link

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...

  • Related