Home > Software engineering >  In Typescript is there a better way to represent the types of an object of arrays
In Typescript is there a better way to represent the types of an object of arrays

Time:10-16

I have an object which contains roles which are an array of rights which they grant e.g.

const allRoles = {
  user: [
    'right1'
  ],
  admin: [
    'right1',
    'right2'
  ],
} as const

If I wanted to get the types for user rights and admin rights I could do:

type userRights = Array<typeof allRoles.user[number]>
type adminRights = Array<typeof allRoles.admin[number]>

And to get the types for both I could do:

type RoleRights = userRights | adminRights

I don't need individual user rights or admin rights. Is there a way I can represent all of the available rights in on type declaration?

Similar to how if I wanted to create an array of all rights I could do:

const roleRights = new Map(Object.entries(allRoles))

CodePudding user response:

Assuming you want to infer your types using as const from the allRoles object, you could do the following:

const allRoles = {
  user: [
    'right1'
  ],
  admin: [
    'right1',
    'right2'
  ],
} as const

type RolesMap = typeof allRoles;
/*
{
  readonly user: readonly ["right1"];
  readonly admin: readonly ["right1", "right2"];
}
*/

type UserRoles = RolesMap['user']; // readonly ["right1"]
type AdminRoles = RolesMap['admin']; // readonly ["right1", "right2"]
type AllRoles = UserRoles | AdminRoles; // readonly ["right1"] | readonly ["right1", "right2"]

Note: This will make fixed types out of ['right1'] and ['right1', 'right2'], you will notice this is therefore not automatically collapsed into something like ('right1' | 'right2')[] which I imagine is what you are after.

However if you already know all of the rights in advance, which I imagine you likely do, architecturally it may make more sense to type the system the other way around, starting from the rights and building up to the map, e.g.

enum RightsEnum {
  right1 = 'right1',
  right2 = 'right2',
  right3 = 'right3',
  ...
}
enum RolesEnum {
  user = 'user',
  admin = 'admin'
}

// explicit
interface RolesMap {
  [RolesEnum.user]: [RightsEnum.right1],
  [RolesEnum.admin]: [RightsEnum.right1, RightsEnum.right2]
}

// generic
type RolesMap = Record<RolesEnum, RightsEnum>;

const allRoles: RolesMap = {
  user: [
    'right1'
  ],
  admin: [
    'right1',
    'right2'
  ],
}

Your "all rights" type would therefore just be RightsEnum

CodePudding user response:


type userRight = typeof allRoles.user[number]
type adminRight = typeof allRoles.admin[number]

type userRights = userRight[]
type adminRights = adminRight[]

type RoleRights = (userRight | adminRight)[]

  • Related