Skip to content

Commit f334dfd

Browse files
authored
Fix params type when the route name is an union (#50)
1 parent 05b6824 commit f334dfd

File tree

6 files changed

+55
-5
lines changed

6 files changed

+55
-5
lines changed

docs/docs/utility-types.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
title: Utility types
3+
sidebar_label: Utility types
4+
---
5+
6+
To easily extract routes types, use `InferRoutes`:
7+
8+
```tsx {1,9}
9+
import { createRouter, InferRoutes } from "@swan-io/chicane";
10+
11+
export const Router = createRouter({
12+
UserList: "/users",
13+
UserDetail: "/users/:userId",
14+
});
15+
16+
// A map of RouteName and its associated RouteParams
17+
type Routes = InferRoutes<typeof Router>;
18+
19+
export type RouteName = keyof Routes;
20+
export type RouteParams<T extends RouteName> = Routes[T];
21+
```

docs/sidebars.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const sidebars = {
2828
"matching-some-routes",
2929
"linking-to-a-route",
3030
"server-side-rendering",
31+
"utility-types",
3132
],
3233
},
3334
{

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@swan-io/chicane",
3-
"version": "2.0.0",
3+
"version": "2.1.0",
44
"license": "MIT",
55
"description": "A simple and safe router for React and TypeScript",
66
"author": "Mathieu Acthernoene <[email protected]>",

src/createRouter.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
ParseRoutes,
2323
PrependBasePath,
2424
RouteObject,
25+
UnionToIntersection,
2526
} from "./types";
2627

2728
export const createRouter = <
@@ -138,12 +139,12 @@ export const createRouter = <
138139

139140
const push = <RouteName extends keyof FiniteRoutes>(
140141
routeName: RouteName,
141-
...params: ParamsArg<FiniteRoutesParams[RouteName]>
142+
...params: ParamsArg<UnionToIntersection<FiniteRoutesParams[RouteName]>>
142143
): void => pushUnsafe(matchToUrl(matchers[routeName], first(params)));
143144

144145
const replace = <RouteName extends keyof FiniteRoutes>(
145146
routeName: RouteName,
146-
...params: ParamsArg<FiniteRoutesParams[RouteName]>
147+
...params: ParamsArg<UnionToIntersection<FiniteRoutesParams[RouteName]>>
147148
): void => replaceUnsafe(matchToUrl(matchers[routeName], first(params)));
148149

149150
return {

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export {
1010
} from "./history";
1111
export { decodeSearch, encodeSearch } from "./search";
1212
export { ServerUrlProvider } from "./server";
13-
export type { Location, Search } from "./types";
13+
export type { InferRoutes, Location, Search } from "./types";
1414
export { useBlocker } from "./useBlocker";
1515
export { useFocusReset } from "./useFocusReset";
1616
export { useLinkProps } from "./useLinkProps";

src/types.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,13 @@ type NonOptionalProperties<T> = Exclude<
171171
undefined
172172
>;
173173

174+
// https://github.com/microsoft/TypeScript/issues/13298#issuecomment-1610361208
175+
export type UnionToIntersection<Union> = (
176+
Union extends never ? never : (_: Union) => never
177+
) extends (_: infer Intersection) => void
178+
? Intersection
179+
: never;
180+
174181
export type ParamsArg<Params> =
175182
Params extends Record<PropertyKey, never>
176183
? []
@@ -180,6 +187,26 @@ export type ParamsArg<Params> =
180187

181188
export type GetCreateURLFns<RoutesParams extends Record<string, Params>> = {
182189
[RouteName in keyof RoutesParams]: (
183-
...params: ParamsArg<RoutesParams[RouteName]>
190+
...params: ParamsArg<UnionToIntersection<RoutesParams[RouteName]>>
184191
) => string;
185192
};
193+
194+
// User land helpers
195+
196+
type RouteLike = {
197+
name: string;
198+
params: Params;
199+
};
200+
201+
type RouterLike = {
202+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
203+
getRoute: (...args: any[]) => RouteLike | undefined;
204+
};
205+
206+
type RemapRoute<Route extends RouteLike> = {
207+
[N in Route["name"]]: Extract<Route, { name: N }>["params"];
208+
};
209+
210+
export type InferRoutes<Router extends RouterLike> = RemapRoute<
211+
NonNullable<ReturnType<Router["getRoute"]>>
212+
>;

0 commit comments

Comments
 (0)