Code Monkey home page Code Monkey logo

react-router-typesafe-routes's People

Contributors

fenok 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

react-router-typesafe-routes's Issues

[Question] Type constraints when passing routes

Hello! Thank you for a very useful library, I enjoy using it in my React projects πŸ‘

I am stuck with implementing a specific scenario. The idea is that route prop should only accept routes with id param in it.
I pass a proper type to Route.TPathTypes, so that I get TS error when trying to pass a route that does not have id param.
But I'm not sure how to figure out a constraint for Route.TPath in the same way.

const idParams = types({ params: { id: string() } }).params;
type IdRoute = Route<string, typeof idParams, any, any, any>;

type Props = {
  route?: IdRoute;
}

const Component = ({ route }: Props) => {
  const path = route.buildPath({})
}

This gives an error as expected.
image

But here, I expect typescript to give me an error as well since I don't pass an id here.
image

What could go wrong if not using uppercase in route names?

Hey, great library!

I saw the in the docs that mention the following:

❗Child routes have to start with an uppercase letter to prevent overlapping with route API.

I was wondering if you could go more in detail of what this means, as I like my routes in lowercase haha.

Thanks!

v6 uninline child

Playing with the v6 branch.
It'd be nice if you could something like

const detailsRoutes = PRODUCT.DETAILS.uninline(PRODUCT).

So you could then use inline children to get the easy dot notation access, but break it apart when creating routes.

Error when bundling

Hi! I've just found this wonderful looking project and would love to use it in one of my project. However, when I bundle my project I get these errors. Any ideas?

✘ [ERROR] No matching export in "node_modules/react-router-dom/esm/react-router-dom.js" for import "useSearchParams"

    node_modules/react-router-typesafe-routes/dom/useTypedSearchParams.js:12:9:
      12 β”‚ import { useSearchParams, createSearchParams } from "react-router-dom";
         β•΅          ~~~~~~~~~~~~~~~

✘ [ERROR] No matching export in "node_modules/react-router-dom/esm/react-router-dom.js" for import "createSearchParams"

    node_modules/react-router-typesafe-routes/dom/useTypedSearchParams.js:12:26:
      12 β”‚ import { useSearchParams, createSearchParams } from "react-router-dom";
         β•΅                           ~~~~~~~~~~~~~~~~~~

✘ [ERROR] No matching export in "node_modules/react-router-dom/esm/react-router-dom.js" for import "createSearchParams"

    node_modules/react-router-typesafe-routes/dom/route.js:1:9:
      1 β”‚ import { createSearchParams, generatePath } from "react-router-dom";
        β•΅          ~~~~~~~~~~~~~~~~~~

Please let me know if there is any more information I can provide to help debug this.

For path `'/'` error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'.

Hi, when I try to use the path value '/' for a route I get the error:

TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. 

This happens only for this value. Feels like there's an explicit check for this value in particular, but I wonder why since I have been always able to use it without issues with react-router?

export const ROUTES = {
  DEFAULT: route('/'), // <- TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. 
};
<Routes>
    <Route
        path={'/'}  // <- not a problem
        element={<MyComponent />}
    />

Cannot declare nested routes

const routes = {
	root: route('', {}, { auth: route('auth', {}) }),
};

Throws

Argument of type '{ auth: RouteWithChildren<void, "auth", Record<never, never>, Record<never, never>, never[], Record<never, never>>; }' is not assignable to parameter of type 'undefined'.

I am using typescript 4.9.4.

Get absolute path without indeterminate stars

Hello,

Thanks for your work on this, I believe it can really help my current project. My organization uses sub-routers to add shared wrappers/organize code specific to a particular kind of entity.

For example:

<Routes>
  <Route path={ROUTES.HOME.path} element={<HomePage />} />
  <Route path={ROUTES.USERS.path} element={<UserRouter />} />
</Routes>

UserRouter would render the following:

<Routes>
  <Route path={ROUTES.USERS.$.LIST.path} element={<UserListPage />} />
  <Route path={ROUTES.USERS.$.DETAILS.path} element={<UserDetailsPage />} />
</Routes>

ROUTES would look something like this:

export const ROUTES = {
  HOME: route(''),
  USERS: route(
    'users/*',
    {},
    {
      LIST: route(''),
      DETAILS: route(':id'),
    }
  ),
};

How would one navigate to ROUTES.USERS.LIST.path while excluding the indeterminate star introduced by USERS route? Does this project support that? relativePath omits it, as noted in the README, but I'm curious if this use case is supported.

console.log(ROUTES.USERS.LIST.path); // prints `users/*`, I'm looking to just print `users/`, potentially at depth (nested routers within nested routers)

Unexpectedly seeing searchParameters pushed through to child routes

If I have a ROUTES like this:

const TEST_ROUTES = {
  EXAMPLE: route(
    'example',
    { searchParams: { q: string() } },
    { DETAILS: route(':id') }
  ),
};

I would expect to want to navigate to example?q=My+query but not example/1?q=My+query. The typescript is letting this go through. If your application is built correctly, this is going to end up rendering fine but will have an awkward URL (and is a sign that your link is being constructed wrong).

Eg: this does not match the @ts-expect-error I want --

// @ts-expect-error - extra search parameters here.
TEST_ROUTES.EXAMPLE.DETAILS.buildPath({ id: '1' }, { q: 'my query' })

Is this a bug or expected behavior? If it's expected, can you help me understand the scenario it's supporting?

Consider renaming buildUrl and buildRelativeUrl functions

Current names are misleading because these functions don't generate full URLs. Instead, they generate URL parts which are called paths in React Router. There already are buildPath and buildRelativePath functions, but they actually generate pathnames, so they can also be renamed.

These are the possible renamings:

  • buildUrl => buildPath
  • buildRelativeUrl => buildRelativePath
  • buildPath => buildPathname
  • buildRelativePath => buildRelativePathname

It won't even be a breaking change, because buildUrl can be safely used instead of buildPath.

Absolute nested routes don't seem to work

First off, thanks for creating this library, I love the concept. It's very possible I'm doing something wrong here.

Your readme says "React Router allows absolute child route paths if they match the parent path." I have a pretty simple structure, and I was able to get it working with relative paths, but not absolute.

I have a parent route /regions/:regionSlug, and the then a child: /regions/:regionSlug/clusters/:id/:clusterName. The child never seems to match.

Here is the typed definition:

const routes = {
  Region: route(
    "regions/:regionSlug",
    {},
    {
      Clusters: route(
        "clusters",
        {},
        {
          List: route(""),
          Details: route(":id/:clusterName"),
        }
      ),
    }
  ),
};

Here is are the actual routes:

<Route path={routes.Region.path} element={<Region />}>
  <Route
    path={routes.Region.Clusters.Details.path}
    element={<ClusterDetails />}
  />
</Route>

The region route matches, but the nested route doesn't.

Add CommonJS support

I'm using react-router-typesafe-routes in a TypeScript project that compiles with Vite. Vite has no issues with the ESM-only output of this package, but I am unable to run my Playwright tests because they require CommonJS imports.

Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/user/Desktop/path/to/project/node_modules/react-router-typesafe-routes/dom/index.js from /Users/user/Desktop/ruter/path/to/project/src/routes.ts not supported.
Instead change the require of index.js in /Users/jonasjensen/Desktop/ruter/bestillingstransport/apps/bt-frontend/src/admin/routing/routes.ts to a dynamic import() which is available in all CommonJS modules.

   at ../src/admin/routing/routes.ts:7

   5 |   OVERVIEW: route('overview'),
   6 |   PROFILE: route('profile'),
>  7 |   TRIPS: route('trips', {}, {LIVE: route('live')}),
     |            ^
   8 |   MORE_ROUTES: route('more_routes', {}, {CLIENTS: route('clients')}),

I unfortunately discovered this only after I'd already rewrite all hardcoded paths in my entire codebase to use react-router-typesafe-routes. 😬 It would be very helpful if the package could support both ESM and CommonJS formats.

It would be great if react-router-typesafe-routes could provide a CommonJS output alongside the ESM output. This would make the package compatible with various testing environments and setups, including those that rely on CommonJS.

(As a workaround, I've tried bundling and transforming my tests using esbuild, but this adds too much extra complexity and I couldn't even get it to work properly..)

Thank you for considering this feature request, and I appreciate your efforts in creating and maintaining this package! I compared all the different "typesafe routes" packages that I could find and this one was by far the best I could find. πŸ™Œ

v6 Direction for path param parsing

We started playing with this package for v6 (which is looking great πŸ‘ ) when it was using parsers like numberParser these threw if it was bad input.
Now with the move to numberType you either pass a fallback or the returned value could be undefined which requires checking for bad input in every route or (just swallowing it by passing -1 or NaN)

Whilst the errors were jarring at first, using an ErrorBoundary you could handle them globally or per nested set of routes, especially if the error thrown was rich.

Curious on what you are thinking for handling parse errors going forward (just rely on fallbacks, is there an option to still throw)?

Route composition API

There are cases when routes can share the same set of parameters (most likely search parameters and state fields). One common example is pagination params.

We likely want a common helper for these parameters as well, so we need an actual route for them.

We could use inheritance, but it can quickly get ugly: PAGINATION.FILTER.ORDER.ACTUAL_ROUTE.buildUrl(...).

We can use route types, but it's relatively verbose:

const PAGINATION_FRAGMENT = route( '', { searchParams: { offset: numberType } } );

const LIST = route( 'list', { searchParams: { ...PAGINATION_FRAGMENT.types.searchParams, customParam: stringType } } )

It would be nice to have an API for route composition, something like this:

const LIST = route( 'list', {searchParams: { customParam: stringType }}, {}, [PAGINATION_FRAGMENT] );

However, I can't figure out how to write types for this (when there are multiple fragments).

Merging typed and non-typed search params

As of now, if we want to implement a common helper which only handles a portion of search params, but leaves other search params intact, we have to resort to using URLSearchParams object.

Thoughts:

  • We could add an option for setTypedSearchParams (of useTypedSearchParams), like preserveNonTyped. If true, the given object is merged with URLSearchParams object (containing only non-typed params).

Questions:

  • Do we need something similar for build* APIs?
  • Do we need to return restUrlSearchParams: URLSearchParams from useTypedSearchParams?

Switch to the latest React Router version

Can this be shared between a backend and frontend app?

My current setup is a monorepo where the URLs are shared between frontend app (using react-router) and a backend app (using node), my concern is that since this relies on react-router it will not work on the backend app, or am I missing something?

`.buildPath` allows invalid arguments

I have an application with heavy use of searchParams and I'm looking for a way to make it harder for developers to invoke buildPath incorrectly.

In the example below, you can see that it's very easy to call buildPath with the searchParameters as the first argument.

I think this is because the first argument to buildPath in this situation is Record<never, never> instead of Record<string, never>.

Any tips on either:
(1) where to fix this in the library
(2) how to build the ROUTES differently to get type safety without any upstream fix
(3) a pointer on if I'm doing something completely wrong.

Thanks!

import { route, string } from 'react-router-typesafe-routes/dom';

const ROUTES = {
  WIDGETS: route('widgets', { searchParams: { order: string() } }),
};

// This is what I want to invoke:
ROUTES.WIDGETS.buildPath({}, { order: 'asc' }); // '/widgets?order=asc'

// This silently fails -- it passes the typescript tests
ROUTES.WIDGETS.buildPath({ order: 'asc' }); // '/widgets'

Consider separating parsing and validation

As of now, parsing and validation are both done via getTyped method. This leads to the following drawbacks:

  • Fallbacks are returned as-is, because they represent parsed values, and there is no way to validate what is already parsed. Therefore, it's possible to specify a fallback that violates validation rules.
  • Types of useTypedSearchParams could be slightly improved. We can specify initial search params, which behave similarly to fallbacks. If we knew which types don't include validation, we could type the corresponding returned params as non-undefined regardless of the fallbacks of their types. Or we could change useTypedSearchParams to accept actual fallbacks and just validate them.

We could split getTyped into required getTyped and optional validate, but it might be inconvenient for creating custom types.

Overall, it's not clear which approach is best.

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.