npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-router-typed-object

v1.0.5

Published

Bringing full typesafety to your React Router configurations

Downloads

586

Readme

React Router Typed Object

Bringing full typesafety to your React Router configurations

Introduction

React Router Typed Object is a helper library for React Router that brings complete typesafety to your route configurations. It enables you to define your routes in a way that TypeScript can infer all the necessary types, ensuring that all router references are consistent and safe across your codebase. This is especially beneficial in large applications with complex routing structures, where maintaining typesafety can greatly reduce errors and improve developer productivity.

By using React Router Typed Object, you can leverage the power of TypeScript to catch errors at compile time, assist in refactoring, and provide better autocompletion and documentation within your code editor. Check more details and examples in the Typesafe references and refactorings docs section.

Open in StackBlitz

Features

  • Seamless Integration: Works with exact react-router's RouteObject type and react-router-dom's "createRouter*" functions.
  • Typesafe Route Definitions: Automatically infer types from your route configurations.
  • Path Parameter Handling: Define routes with dynamic parameters and get type-checked path generation.
  • Search Parameter Validation: Use any validation library you like to define and validate search parameters.

Installation

To install React Router Typed Object, use npm or yarn:

npm install react-router-typed-object @remix-run/router

@remix-run/router explicit installation is needed to allow correct type inference.

Usage

Here's how you can use React Router Typed Object in your project.

Defining Routes with inferRouteObject

The inferRouteObject function allows you to define your routes and automatically infer their types.

import { inferRouteObject } from "react-router-typed-object";

export const ROUTES = inferRouteObject({
  path: "a",
  children: [
    { path: "b" },
    {
      path: "c",
      children: [{ children: [{ children: [{ path: "d" }] }] }],
    },
  ],
});

This will create a ROUTES object that contains typed paths for all nested routes.

Generating Paths with Parameters

You can define routes with path parameters, and inferRouteObject will ensure that you provide the correct parameters when generating paths.

export const ROUTES = inferRouteObject({
  path: "a/:b",
  children: [{ path: "c/:d" }],
});

const path = ROUTES["/a/:b/c/:d"].path({ b: "B", d: "D" });
// path is "/a/B/c/D"

If you try to omit required parameters or provide incorrect ones, TypeScript will show an error.

Handling Search Parameters with Validation

You can define search parameters using any type predicate, which give you both typesafety and runtime validation.

import { z } from "zod";

export const ROUTES = inferRouteObject({
  path: "a/:b",
  children: [
    {
      path: "c/:d",
      searchParams: z.object({
        z: z.string(),
        q: z.string().optional(),
      }).parse, // NOTE the `.parse`, we need only a validation function
    },
  ],
});

const path = ROUTES["/a/:b/c/:d"].path({ b: "B", d: "D", z: "Z" });
// path is "/a/B/c/D?z=Z"

If you provide invalid search parameters, the validation function will throw an error at runtime, ensuring your app only navigates to valid URLs.

Using typesafe paths with a router

"ROUTES" is your source of truth. You can use it to get a typesafe access to your routes in all other related APIs.

<Route path={ROUTES["/a/:b/c/:d"].path.pattern} />

OR, of course:

import { createBrowserRouter } from "react-router-dom";

export const router = createBrowserRouter([ROUTES]);
const navigate = useNavigate();
const toD = (b: string, d: string) => {
  navigate(ROUTES["/a/:b/c/:d"].path({ b, d }));
};

<a onClick={() => toD("B", "D")}>Go to D</a>;

Navigating with built in createRouter

You can use your "ROUTES" object to get a typesafe access to your routes

The createRouter function creates a router instance with typesafe navigate method which added to every "path".

import { createRouter } from "react-router-typed-object";
import { z } from "zod";

const ROUTER = createRouter([
  {
    path: "a",
    children: [
      {
        path: ":b/c/:d",
        searchParams: z.object({ z: z.string() }).parse,
      },
    ],
  },
]);

ROUTER["/a/:b/c/:d"].path.navigate({ b: "B", d: "D", z: "Z" });
// `location.href` is "/a/B/c/D?z=Z"

The .navigate() method of a router path is just a tiny bind function from the path to router navigate method.

Typesafe references and refactorings

The motivation behind creating this library stemmed from working on a large legacy project with a massive route configuration exceeding 1,000 lines of code. Managing and maintaining such a large configuration was challenging. It was easy to make mistakes like creating duplicate paths or unintentionally removing or modifying routes that were used elsewhere in the application.

React Router Typed Object addresses these issues by allowing developers to define a strict list of all routes with full typesafety. The "path" property becomes a crucial element to synchronize type references between route usages and route definitions. With this library, you can use TypeScript's powerful tooling to find all route usages from the configuration or locate the relevant configuration part from a usage point. This ensures consistency and reduces the likelihood of errors in your routing logic.

Open this example on StackBlitz:

Open in StackBlitz

image

image

API Reference

inferRouteObject(routeConfig, basename = '')

Generates a typesafe routes object from the given route configuration. The configuration is exactly import { type RouteObject } from "react-router", but with additional searchParams property with a validation function.

  • Parameters:
    • routeConfig: An object representing the route configuration. It is same object from original React Router (import { type RouteObject } from "react-router"). Each route can include path, children, and additional searchParams validation function.
    • basename: optional starting path.
  • Returns: The same route object with additional "\${string}" properties which includes full routes paths in any depth of the config.

createRouter(routeConfig, options)

Creates a router instance with typesafe navigation methods.

  • Parameters:
    • routeConfig: The same route configuration used in inferRouteObject.
    • options:
      • all original options from createBrowserRouter.
      • basename: optional starting path.
      • createRouter: optional router creation function, defaults to createBrowserRouter.
  • Returns: A router instance with navigation methods and all "\${string}" routes from inferRouteObject