Git Product home page Git Product logo

typesafe-react-router's Introduction

Typesafe-React-Router

A collection of types and utility functions to facilitate typesafe routing in React-Router.

npm i typesafe-react-router

vscode Note: This gif is using the 1.0 array-style API, rather than spread arguments used in 2.0.

Usage

import { route, param } from 'typesafe-react-router';

export enum RouteNames {
  HOME = "HOME"
  VIEW_ALL = "VIEW_ALL"
  VIEW_DETAILS = 'VIEW_DETAILS'
}

export const Routes = {
  [RouteNames.HOME]: route('home');
  [RouteNames.VIEW_ALL]: route('view')
  [RouteNames.VIEW_DETAILS]: route('view', param('id'))
}

const viewDetailsTemplate = Routes[RouteNames.VIEW_DETAILS].template() // -> /view/:id
const viewDetailsCreate = Routes[RouteNames.VIEW_DETAILS].create({ id: '2' }) // -> /view/2

const viewDetailsCreateERROR = Routes[RouteNames.VIEW_DETAILS].create({}) // ERROR: property 'id' is missing in type {}

// Usage with React Router
import { Route, Switch } from 'react-router-dom';
import { Home, Summary, Details } from './components'
export class App extends React.PureComponent {
  render() {
    <Switch>
      <Route path={Routes[RouteNames.HOME].template()} component={Home} />
      <Route path={Routes[RouteNames.VIEW].template()} component={Summary} />
      <Route path={Routes[RouteNames.VIEW_DETAILS].template()} component={Details} />
    </Switch>
  }
}

import { Link } from 'react-router-dom';

export class Home extends React.PureComponent {
  render() {
    <div>
      <h1>Welcome Home!</h1>
      <Link to={Routes[RouteNames.VIEW_DETAILS].create({ id: '3' })} />
      {/* ERROR: property 'id' is missing in type {} */}
      <Link to={Routes[RouteNames.VIEW_DETAILS].create({})} />
    </div>
  }
}

typesafe-react-router's People

Contributors

erin-noe-payne avatar igorrmotta avatar ksaldana1 avatar mfranklin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

typesafe-react-router's Issues

RouteParams & QueryParams

I love this lib, simple and focused.

I think you may want to spend another hour of work to:

  • add QueryParams type, modelled after RouteParams
  • add documentation for QueryParams & RouteParams
  • add documentation for how to type ReactRouter's Route component's params

User-land typesafe usage example of ReactRouter Route component:

import React from "react";
import { Route as RouteComponent, RouteProps, RouteComponentProps } from "react-router-dom";
import { RouteParams, Route } from "typesafe-react-router";

type QueryParams<T> = T extends Route<any, infer Y> ? Partial<Record<Y[number], string>> : never;

interface MatchProps<R extends Route<any, any>>
  extends Omit<RouteProps, "path" | "render" | "component" | "children"> {
  route: R;
  component?: React.ComponentType<RouteComponentProps<RouteParams<R>>>;
  render?: (
    params: RouteParams<R> & QueryParams<R>,
    allProps: RouteComponentProps<RouteParams<R>>
  ) => React.ReactNode;
  children?: (props: RouteComponentProps<RouteParams<R>>) => React.ReactNode;
}

// Simple typesafe ReactRoute `Route` component wrapper. Not nestable in ReactRouter `Switch` component.

// `render` prop.
// Renders only when matching.
// Similar to `ReactRouter Route#render`, but first argument is params/search_params hash:
//   Explicitely access match params/search_params hash.
//     <Match route={Routes.project.template()} render={({ projectId }) => <Project projectId={projectId} />} />
//   Project -since it is a function- gets the first render arg. (i.e. params/search_params) mixed in the props.
//   So the previous example can be written:
//     <Match route={Routes.project.template()} render={Project} />
//   Explicitely access ReactRouter props (second arg.).
//     <Match route={Routes.project.template()} render={(_, { history, location, match, staticContext }) => <Project projectId={match.params.projectId} /> } />

// `component` prop.
// Renders only when matching.
// Identical to `ReactRouter Route#component`:
// Project gets ReactRouter props mixed in his props. `projectId` is accessible with `props.match.params.projectId`.
//    <Match route={Routes.project.template()} component={Project} />

// `children` prop
// ALWAYS renders
// Identical to `ReactRouter Route#children`. Only the "function as a children" form is typesafe.
//   <Match route={Routes.project.template()}>
//     {({ history, location, match, staticContext }) =>
//       match ? <Project projectId={match.params.projectId} /> : null}
//   </Match>

const Match = <R extends Route<any, any>>({
  route,
  render,
  component,
  ...routeProps
}: MatchProps<R>) => (
  <RouteComponent
    {...routeProps}
    path={route.template()}
    render={props =>
      render
        ? render({ ...props.match.params, ...route.parse(props.location.search) }, props)
        : component
        ? React.createElement(component, props)
        : undefined
    }
  />
);

export default Match;

Decoding + encoding typed data from the stringly typed params

Hi!

I had a need for this kind of type safe routing a coupe of months ago. I didn't find any library, so I implemented my own. The basic idea is very similar to yours, but has some pros and cons.

https://github.com/geon/routes/blob/master/usage.ts

Typed Params

Most importantly, my routes has properly typed params, not just named strings. I do this by passing a parse function to the route creator. This function converts a {[paramName: string]: string} to a type object of type TParams.

The parameters are also validated. They can be checked to conform to some regex, or checked to exist in an array, etc.

The output-ed typed params object does not need to have the same number of properties ar the input. Properties like pageNumberand pageSize can be lumped together into a pagination object.

This was invaluable when developing our app.

Crumbs

A minor but neat feature I implemented was bread crumb generation. Each route has a function that takes params and returns a title string. Optionally, it also has a previous page route. Using this, we can easily generate an array of titles + hrefs, that can be rendered as a bread crumb.

Change module to be CommonJS instead of ES2015

Problem

When transpiling the module we're doing from typescript down to ES2015 javascript. Not every bundler/browser can read ES2015 as of yet.

Solution

Could we instead transpile the module to CommonJS. Making it compatible with legacy browsers and tools?

Seeing `Cannot find module 'typesafe-react-router'` issues in 2.2.0

I had just upgraded node modules and noticed that typesafe-react-router was updated.

Builds are all of a sudden causing an issue:

ERROR in ./src/routes.ts
Module not found: Error: Can't resolve 'typesafe-react-router' in '/Users/jason/go/src/***/***/projectname/src'

I created a demo project and had the same problems:

https://github.com/jasonraimondi/trr-issue-example-repo

I was able to hard version to 2.0.0 so it is not a huge problem, but it does seem to be consistently happening in separate projects of mine, so it may start revealing itself to others.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.