DEV Community

Cover image for Type-safe routing with Typescript and Route Maps
Matt Pocock
Matt Pocock

Posted on

Type-safe routing with Typescript and Route Maps

Routing in web apps can be a subtle, but persistent source of bugs. You think you've updated every reference to a route you're changing, and BAM. You've caused a bug in some unrelated part of your app.

This gets worse when you need to add path parameters (/user/:id/edit) and search parameters (/auth?redirectPath=somewhere). Usually, this leads to a ton of string concatenation clogging up your code, and a mess of routes that are hard to maintain.

That's why I built make-route-map, an npm package which helps get your routing under control. It's 100% Typescript, and it lets you create a gorgeous, clean API for your routing which has type-safe routes, path parameters and search parameters.

I can't tell you how much stress it's saved me already. Refactoring or removing a route no longer takes dozens of find-in-files to remove the references. All that stress is Typescripted away.

The Basics

import { makeRouteMap } from 'make-route-map';

const routeMap = makeRouteMap({
  users: {
    path: '/users',
  },
  editUser: {
    path: '/users/:id/edit',
    params: {
      id: true,
    },
  },
  auth: {
    path: '/auth',
    search: {
      redirectPath: true,
    },
  },
});

console.log(routeMap.users());
// '/users'

console.log(routeMap.editUser({ params: { id: '240' } });
// '/users/240/edit'

console.log(
  routeMap.auth({
    search: { redirectPath: 'somewhere' },
  }),
);
// /auth?redirectPath=somewhere

Enter fullscreen mode Exit fullscreen mode

The makeRouteMap function just creates a set of helpers which pull out the routes. You can pass in path parameters and search parameters.

Navigating

makeNavigate can take in a routeMap and a function to send you to a route, and will navigate you there when it's called.

const goToRoute = route => {
  window.location.href = route;
};

const navigate = makeNavigate(routeMap, goToRoute);

// This would take the user to '/users/240/edit'
navigate.editUser({
  params: {
    id: '240',
  },
});
Enter fullscreen mode Exit fullscreen mode

This means you can plug in navigate into your current navigation implementation, like history.push.

Try it out

The repo
The package

Let me know how you get on, and if you have any requests for the API. I'm so excited to have a pattern that's been working wonders for us public available.

Discussion (2)

Collapse
g_abud profile image
Gabriel Abud

Thanks! Would love the follow up on how to test an E2E map with Cypress and/or react-testing-library if you've done so :). I supposed it'd need to be RTL maybe since Cypress is at the browser level so you may not be able to import this hook?

Collapse
phawk profile image
Pete Hawkins

This is awesome, I was just searching for how to do typesafe routes and your library came up, really slick!