Skip to content

Commit

Permalink
Fix params type when the route name is an union (#50)
Browse files Browse the repository at this point in the history
  • Loading branch information
zoontek authored Jul 22, 2024
1 parent 05b6824 commit f334dfd
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 5 deletions.
21 changes: 21 additions & 0 deletions docs/docs/utility-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: Utility types
sidebar_label: Utility types
---

To easily extract routes types, use `InferRoutes`:

```tsx {1,9}
import { createRouter, InferRoutes } from "@swan-io/chicane";

export const Router = createRouter({
UserList: "/users",
UserDetail: "/users/:userId",
});

// A map of RouteName and its associated RouteParams
type Routes = InferRoutes<typeof Router>;

export type RouteName = keyof Routes;
export type RouteParams<T extends RouteName> = Routes[T];
```
1 change: 1 addition & 0 deletions docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const sidebars = {
"matching-some-routes",
"linking-to-a-route",
"server-side-rendering",
"utility-types",
],
},
{
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@swan-io/chicane",
"version": "2.0.0",
"version": "2.1.0",
"license": "MIT",
"description": "A simple and safe router for React and TypeScript",
"author": "Mathieu Acthernoene <[email protected]>",
Expand Down
5 changes: 3 additions & 2 deletions src/createRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
ParseRoutes,
PrependBasePath,
RouteObject,
UnionToIntersection,
} from "./types";

export const createRouter = <
Expand Down Expand Up @@ -138,12 +139,12 @@ export const createRouter = <

const push = <RouteName extends keyof FiniteRoutes>(
routeName: RouteName,
...params: ParamsArg<FiniteRoutesParams[RouteName]>
...params: ParamsArg<UnionToIntersection<FiniteRoutesParams[RouteName]>>
): void => pushUnsafe(matchToUrl(matchers[routeName], first(params)));

const replace = <RouteName extends keyof FiniteRoutes>(
routeName: RouteName,
...params: ParamsArg<FiniteRoutesParams[RouteName]>
...params: ParamsArg<UnionToIntersection<FiniteRoutesParams[RouteName]>>
): void => replaceUnsafe(matchToUrl(matchers[routeName], first(params)));

return {
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export {
} from "./history";
export { decodeSearch, encodeSearch } from "./search";
export { ServerUrlProvider } from "./server";
export type { Location, Search } from "./types";
export type { InferRoutes, Location, Search } from "./types";
export { useBlocker } from "./useBlocker";
export { useFocusReset } from "./useFocusReset";
export { useLinkProps } from "./useLinkProps";
29 changes: 28 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,13 @@ type NonOptionalProperties<T> = Exclude<
undefined
>;

// https://github.com/microsoft/TypeScript/issues/13298#issuecomment-1610361208
export type UnionToIntersection<Union> = (
Union extends never ? never : (_: Union) => never
) extends (_: infer Intersection) => void
? Intersection
: never;

export type ParamsArg<Params> =
Params extends Record<PropertyKey, never>
? []
Expand All @@ -180,6 +187,26 @@ export type ParamsArg<Params> =

export type GetCreateURLFns<RoutesParams extends Record<string, Params>> = {
[RouteName in keyof RoutesParams]: (
...params: ParamsArg<RoutesParams[RouteName]>
...params: ParamsArg<UnionToIntersection<RoutesParams[RouteName]>>
) => string;
};

// User land helpers

type RouteLike = {
name: string;
params: Params;
};

type RouterLike = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getRoute: (...args: any[]) => RouteLike | undefined;
};

type RemapRoute<Route extends RouteLike> = {
[N in Route["name"]]: Extract<Route, { name: N }>["params"];
};

export type InferRoutes<Router extends RouterLike> = RemapRoute<
NonNullable<ReturnType<Router["getRoute"]>>
>;

0 comments on commit f334dfd

Please sign in to comment.