Home > Back-end >  Restricting object key type with const
Restricting object key type with const

Time:05-13

I am able to define an object key type from a union like:

type Action = 'foo' | 'bar' | 'baz';

type UserStates = 'active' | 'deleted' | 'dishonoured';

type Permission = {
  [key in UserStates]: Action[];
};

However, I have a scenario where the options are const literals like:

const UserStates = ['active', 'deleted', 'dishonoured'] as const;
const Action = ['foo', 'bar', 'baz'] as const;

type Permission = {
  [key: typeof UserStates[number]]: typeof Action[number][];
};

This results in:

error TS1337: An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead.

How should I define the key signature if this scenario?

Working Example for union types:

type Action = 'foo' | 'bar' | 'baz';

type UserStates = 'active' | 'deleted' | 'dishonoured';

type Permission = {
  [key in UserStates]: Action[];
};

export const PERMISSIONS: Permission = {
  active: ['foo', 'bar', 'baz'],
  deleted: ['bar'],
  dishonoured: ['baz'],
};

const hasPermission = (userState: UserStates, action: Action): boolean =>
  PERMISSIONS[userState].some((x) => x === action);

console.info(hasPermission('active', 'foo'));
console.info(hasPermission('deleted', 'foo'));

CodePudding user response:

A Record instead will work:

type Permission = Record<typeof UserStates[number], typeof Action[number][]>;

This results in the type:

type Permission = {
    active: ("foo" | "bar" | "baz")[];
    deleted: ("foo" | "bar" | "baz")[];
    dishonoured: ("foo" | "bar" | "baz")[];
}

CodePudding user response:

You almost had it:

type Permission = {
  [key in typeof UserStates[number]]: typeof Action[number][];
};
  • Related