For the code below, I'd like to extract the keys of routes
.
type Route = {
url: string
auth: boolean
}
type Routes = Record<string, Route>
const routes: Routes = {
add: {
url: '/comment',
auth: false
},
delete: {
url: '/comment',
auth: true
}
}
If I define keys as this:
type RouteKeys = keyof typeof routes
the RouteKeys transpiles to string
because infers from Record<string>
, fine - but I'd like it to be 'add' | 'delete'
.
When I try:
type Routes = Record<keyof typeof routes, Route>
then I receive a TypeScript error "Type alias Routes circularily references itself" which is fair too.
I understand if I define:
type RouteKeys = 'add' | 'delete'
and assign it to Routes it will work, but this will force me to manually make changes to type every time there is a new route. Alternatively I am forced to give up on "Route" type in Routes which is not ideal as I work further on this type conditionally.
Is there a way to obtain keys and keep the "Routes" type without hardcoding them anywhere but also keep the Route type values specified?
You can use the satisfies
operator to guarantee that the values of the properties of routes
are all assignable to Route
:
const routes = {
add: {
url: '/comment',
auth: false
},
delete: {
url: '/comment',
auth: true
}
} satisfies { [k: string]: Route }
That breaks the potential circularity so now you can define Routes
in terms of typeof routes
:
type Routes = Record<keyof typeof routes, Route>
In this version, routes
has a type somewhat narrower than Routes
because the values might be subtypes of Route
. If you need routes
to be exactly of type Routes
you can always rename it out of the way to start and then copy the result:
const _routes = {
add: {
url: '/comment',
auth: false
},
delete: {
url: '/comment',
auth: true
}
} satisfies { [k: string]: Route }
type Routes = Record<keyof typeof _routes, Route>
const routes: Routes = _routes;