Skip to content

Instantly share code, notes, and snippets.

@mikew
Created December 29, 2022 21:39
Show Gist options
  • Save mikew/17ab6762a05c58ace157b536ee5cf7ee to your computer and use it in GitHub Desktop.
Save mikew/17ab6762a05c58ace157b536ee5cf7ee to your computer and use it in GitHub Desktop.
Route Path
import {
generatePath,
matchPath,
useParams,
ExtractRouteParams,
} from 'react-router'
import history from './history'
// Routes have parameters, and it's important to know about them.
// Routes shouldn't be built by hand. It's error-prone and makes changes
// difficult.
// This aims to get around that.
// In a file like `userRoutes.ts`:
// const userDetails = routePath('/users/:id')
// In a react router:
// <Route component={UserDetails} path={userDetails.path} />
// Get the params in a react component:
// const params = userDetails.useParams()
// Build a route for navigation:
// history.push(userDetails.build({ id: '1234' }))
function routePath<
S extends string,
O extends Record<string, any> = ExtractRouteParams<S, string>,
>(path: S) {
return {
/** The path to use when defining a route. */
path,
/** Build a url from an object. */
build: (opts: O) => {
// Hm, this is weird.
// Can't simply pass `opts`, TS complains that the types aren't right.
// `O` is literally the exact type `generatePath` expects there.
// This double-cast clears that.
return generatePath(path, opts as unknown as ExtractRouteParams<S>)
},
/** Attempt to match and parse a url. */
match: (pathName = history.location.pathname) => {
return matchPath<O>(pathName, path)
},
// TODO Could not find a way to easily do
// `useParams<RouteParamsType<myRoute>>` or
// `useParams<myRoute['ParamsType']>`. This works well.
/** Hook to easily get typed route params. */
useParams: () => {
return useParams<O>()
},
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment