Reputation: 36846
Is there a way to Pick (or any other solution) from literal type for connection to main Roles interface?
Reason for this, if i in future will change or delete something in Roles, i can see where i need to change/delete it to.
type Roles = 'admin' | 'user' | 'guest'
// no connection to Roles
type ApiRoute = { roles: 'admin' | 'user' }
// how to?
type ApiRouteWithCheck = { roles: Pick<Roles, 'admin' | 'user'> }
Upvotes: 15
Views: 5721
Reputation: 3928
Given that Extract
doesn't help with type safety, as it doesn't enforce the picked values to be a strict subset of given type, here an alternative.
Create a new helper type:
export type PickStringLiteral<A, B extends A> = B;
Use it like:
type Roles = 'admin' | 'user' | 'guest'
type ApiRouteWithCheck = { roles: PickStringLiteral<Roles, 'admin' | 'user'> }
It does what you expect:
'admin' | 'user'
'admin'
or 'user'
is missing from Roles
Upvotes: 2
Reputation: 122032
You can either Exclude
the values you don't want:
type ApiRoute = { roles: Exclude<Roles, 'guest'> };
or Extract
the values you do:
type ApiRoute = { roles: Extract<Roles, 'admin' | 'user'> };
Upvotes: 27
Reputation: 11770
Another way is to split it up into different types and export types based on those types, this way if you add new types in the future you just add them to AllRoles
and if you need to use one of those types you can just import them directly instead of picking/excluding them
export type AdminRoles = 'admin' | 'superadmin'
export type UserRoles = 'user'
export type PublicRoles = 'guest'
export type AllRoles = AdminRoles | UserRoles | PublicRoles
export type AuthRoles = Exclude<AllRoles, PublicRoles>
Now in the future if you add another type of role you can just add it to AllRoutes
because we are excluding PublicRoles
export type AdminRoles = 'admin' | 'superadmin'
export type ModeratorRoles = 'moderator' | 'supermoderator'
export type UserRoles = 'user' | 'superuser'
export type PublicRoles = 'guest'
export type AllRoles = AdminRoles | UserRoles | PublicRoles | ModeratorRoles
export type AuthRoles = Exclude<AllRoles, PublicRoles>
Upvotes: 0
Reputation: 72226
Change Roles
to be an enum
. This way its name must be used where its values are used.
When you add new values to Roles
you can use "find in files" (or the "code lens" feature of VSCode) to find out where it is used.
enum Roles { admin = 'admin', user = 'user', guest = 'guest' }
type ApiRoutePublic = { roles: Roles }
type ApiRouteAuth = { roles: Roles.admin | Roles.user }
type ApiRouteAdmin = { roles: Roles.admin }
Upvotes: 1