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,
},
};
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,
},
};