I'm not entirely sure if I'm calling this right so I'll explain.
I'm creating React app using TypeScript, in order to make my life simpler I want to store all routings paths as constants separately, I also want to have TypeScript like auto-completion in VS Code. So I have this king of structure:
type GlobalRoutingT = 'user' | 'listing';
type RoutingVariants = {
list: string,
add: string,
get: string,
[key: string]: RoutingVariants | string,
};
type RouterT = Record<GlobalRoutingT, RoutingVariants>;
export const Routes: RouterT = {
user: {
list: '/user',
add: '/user/add',
get: '/user/:id',
invoices: {
list: '/user/invoices',
add: '/user/invoices/add',
get: '/user/invoices/:id',
}
},
listing: {
list: '/listing',
add: '/listing/add',
get: '/listing/:id',
},
};
It works all great I can use it like this at the moment
<Route path={Routes.user.invoices.get} exact >
<GetInvoice />
</Route>
But inside VS Code I get error:
Property 'get' does not exist on type 'string | RoutingVariants'. Property 'get' does not exist on type 'string'.
and Routes.user.invoices.get part is highlighted.
What am I doing wrong?
CodePudding user response:
It looks like what you want isn't exactly possible: How to combine known interface properties with a custom index signature?
You can't combine an index signature with named keys on the same interface / type.
As a workaround, you could use a "child" property, like this:
type GlobalRoutingT = 'user' | 'listing';
type RoutingVariants = {
list: string,
add: string,
get: string,
child?: Record<string, RoutingVariants>
};
type RouterT = Record<GlobalRoutingT, RoutingVariants>;
export const Routes: RouterT = {
user: {
list: '/user',
add: '/user/add',
get: '/user/:id',
child: {
invoices: {
list: '/user/invoices',
add: '/user/invoices/add',
get: '/user/invoices/:id'
}
}
},
listing: {
list: '/listing',
add: '/listing/add',
get: '/listing/:id'
}
};
const a = Routes.user.child?.invoices.get;
Notice how I have to use ?.
to access the child, as it's optional on the type definition.
You could replace child
with something shorter, a single letter, $
or _
...
CodePudding user response:
You need to force the type cast, try this:
<Route path={(Routes.user.invoices as RoutingVariants).get} exact >
<GetInvoice />
</Route>