Home > Back-end >  enum type: is missing the following properties from type
enum type: is missing the following properties from type

Time:05-13

I have some types defined as following:

export type Permission = keyof typeof UserPermissions | undefined;

export type Role = keyof typeof UserRoles;

export type PermissionMap = {
  [P in UserPermissions]: { [R in UserRoles]: boolean };
};

UserPermissions :

enum UserPermissions {
  A = 'A',
  B = 'B',
  C = 'C',
  D = 'D',
  E = 'E',
}

UserRoles:

enum UserRoles {
  ADMIN = 'ADMIN',
  STANDARD = 'STANDARD',
}

When I define an object of type PermissionMap as following:

const permissions: PermissionMap = {
  [UserPermissions.A]: {
    [UserRoles.STANDARD]: false,
    [UserRoles.ADMIN]: true,
  },
  [UserPermissions.B]: {
    [UserRoles.STANDARD]: false,
    [UserRoles.ADMIN]: true,
  },
  [UserPermissions.C]: {
    [UserRoles.STANDARD]: true,
    [UserRoles.ADMIN]: true,
  },
};

I get the following error:

Type '{ A: { STANDARD: false; ADMIN: true; }; B: { STANDARD: false; ADMIN: true; }; C: { STANDARD: true; ADMIN: true; }; }' is missing the following properties from type 'PermissionMap': D, E

And in another case:

const permissions: PermissionMap = {
      [UserPermissions.A]: {
        [UserRoles.ADMIN]: true,
      },
      [UserPermissions.B]: {
        [UserRoles.ADMIN]: true,
      },
      [UserPermissions.C]: {
        [UserRoles.ADMIN]: true,
      },
    };

I get the following error:

Type of computed property's value is '{ ADMIN: true; }', which is not assignable to type '{ ADMIN: boolean; STANDARD: boolean; }'.
Property 'STANDARD' is missing in type '{ ADMIN: true; }' but required in type '{ ADMIN: boolean; STANDARD: boolean; }'.ts(2418)

How can I solve this ?

CodePudding user response:

THis type:

export type PermissionMap = {
  [P in UserPermissions]: { [R in UserRoles]: boolean };
};

Means that there are required all UserPermissions keys: A, B, C, D, E whereas in const permissions you are using only A, B, C. If this is intentional, you can exclude D, E keys from UserPermissions.

So, you can parametrize PermissionMap type:


enum UserPermissions {
    A = 'A',
    B = 'B',
    C = 'C',
    D = 'D',
    E = 'E',
}

enum UserRoles {
    ADMIN = 'ADMIN',
    STANDARD = 'STANDARD',
}

export type Permission = keyof typeof UserPermissions | undefined;

export type Role = keyof typeof UserRoles;

export type PermissionMap<Without extends string = never> = {
    [P in Exclude<UserPermissions, Without>]: { [R in UserRoles]: boolean };
};

const permissions: PermissionMap<UserPermissions.D | UserPermissions.E> = {
    [UserPermissions.A]: {
        [UserRoles.STANDARD]: false,
        [UserRoles.ADMIN]: true,
    },
    [UserPermissions.B]: {
        [UserRoles.STANDARD]: false,
        [UserRoles.ADMIN]: true,
    },
    [UserPermissions.C]: {
        [UserRoles.STANDARD]: true,
        [UserRoles.ADMIN]: true,
    },
};

playground

Or you can use Partial utility type:


enum UserPermissions {
    A = 'A',
    B = 'B',
    C = 'C',
    D = 'D',
    E = 'E',
}

enum UserRoles {
    ADMIN = 'ADMIN',
    STANDARD = 'STANDARD',
}

export type Permission = keyof typeof UserPermissions | undefined;

export type Role = keyof typeof UserRoles;

export type PermissionMap = Partial<{
    [P in UserPermissions]: { [R in UserRoles]: boolean };
}>

const permissions: PermissionMap = {
    [UserPermissions.A]: {
        [UserRoles.STANDARD]: false,
        [UserRoles.ADMIN]: true,
    },
    [UserPermissions.B]: {
        [UserRoles.STANDARD]: false,
        [UserRoles.ADMIN]: true,
    },
    [UserPermissions.C]: {
        [UserRoles.STANDARD]: true,
        [UserRoles.ADMIN]: true,
    },
};

Playground

  • Related