简体   繁体   中英

Configuration based React Router in TypeScript throwing eslint errors

Okay, as I look through the docs for React Router, I see that the suggestion is to use the new routers that support the standard Data History Web APIs , which are relatively new.

I'm in a browser, so I'm going to use createBrowserRouter .

There's some sample code there in JavaScript. I need to port this to TypeScript for my project.

import * as React from "react";
import * as ReactDOM from "react-dom";
import {
  createBrowserRouter,
  RouterProvider,
} from "react-router-dom";

import Root, { rootLoader } from "./routes/root";
import Team, { teamLoader } from "./routes/team";

const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    loader: rootLoader,
    children: [
      {
        path: "team",
        element: <Team />,
        loader: teamLoader,
      },
    ],
  },
]);

ReactDOM.createRoot(document.getElementById("root")).render(
  <RouterProvider router={router} />
);

When I do, I have errors.

I tried removing most of the stuff I don't think I need, like the loaders, etc.

Here's my first cut:

import React from 'react';
import ReactDOM from 'react-dom/client';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import type { BrowserRouter } from 'react-router-dom';
import AnItem from './components/Shared/AnItem';

const myRouter: BrowserRouter = createBrowserRouter([
    {
        path: '/',
        element: <AnItem />,
    },
]);

ReactDOM.createRoot(document.getElementById('root')!).render(
    <React.StrictMode>
        <RouterProvider router={myRouter} />
    </React.StrictMode>
);

There, I get a number of issues about any values, starting with the following line:

const myRouter: BrowserRouter = createBrowserRouter([

There are three errors reported just for that line (I'll include them all in a screenshot, below):

  • Unsafe assignment of an any value.
  • 'BrowserRouter' refers to a value, but is being used as a type here. Did you mean 'typeof BrowserRouter'?
  • Unsafe call of an any typed value.

VS Code 中显示的错误

What's wrong there? I've typed myRouter . I get that the array is untyped for createBrowserRouter , but I thought it could infer.

But let's pull it out and strongly type that array.

import React from 'react';
import ReactDOM from 'react-dom/client';
import type { RouteObject } from 'react-router';
import type { BrowserRouter } from 'react-router-dom';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import AnItem from './components/Shared/AnItem';

const routes: RouteObject[] = [
    {
        path: '/',
        element: <AnItem />,
    },
];

const myRouter: BrowserRouter = createBrowserRouter(routes);

ReactDOM.createRoot(document.getElementById('root')!).render(
    <React.StrictMode>
        <RouterProvider router={myRouter} />
    </React.StrictMode>
);

Now it's happy through routes but still yells at me for...

const myRouter: BrowserRouter = createBrowserRouter(routes);

Unsafe assignment of an any value.

VS Code 弹出窗口解释了任何值的不安全赋值。

Where is the any ? Is it from createBrowserRouter somehow? If I mouseover in VS Code, I get "intellisense" (if that's still what it's called), so I think my types, etc, are all mapping correctly:

(alias) createBrowserRouter(routes: RouteObject[], opts?: {
    basename?: string | undefined;
    hydrationData?: Partial<Pick<RouterState, "loaderData" | "actionData" | "errors">> | undefined;
    window?: Window | undefined;
} | undefined): Router
import createBrowserRouter

That says pretty clearly it returns a Router .

It looks like it can't figure out what BrowserRouter is from that type BrowserRouter = /*unresolved*/ any . But when I mouseover the import, I get:

(alias) function BrowserRouter({ basename, children, window, }: BrowserRouterProps): JSX.Element
import BrowserRouter
A <Router> for use in web browsers. Provides the cleanest URLs.

'BrowserRouter' is declared but its value is never read.ts(6133)

So that seems in context too, though the "its value is never read" is surprising.

Now I did try to type myRouter as a Router , but I get yelled at that I should use a more specific type of router:

Note: You usually won't render a directly [sic]. Instead, you'll render a router that is more specific to your environment such as a in web browsers or a for server rendering.

So I'm using BrowserRouter . But its error is:

'BrowserRouter' refers to a value, but is being used as a type here. Did you mean 'typeof BrowserRouter'?

I'm pretty sure I don't mean typeof ; I'm defining a variable as a specifc type.

What am I missing here? I'm having a hard time googling up an example that both uses configuration instead of components for routing (and I think configuration is what I want as the new Data History API routers require it) and is in TypeScript.

Looks like Drew's on to something. Here are my dependencies from package.json:

    "dependencies": {
        "bootstrap": "^5.2.3",
        "react": "^18.2.0",
        "react-bootstrap": "^2.7.0",
        "react-dom": "^18.2.0",
        "react-router": "^6.7.0",
        "react-router-dom": "^6.7.0"
    },
    "devDependencies": {
        "@types/react": "^18.0.26",
        "@types/react-dom": "^18.0.9",
        "@typescript-eslint/eslint-plugin": "^5.48.2",
        "@typescript-eslint/parser": "^5.48.2",
        "@vitejs/plugin-react-swc": "^3.0.0",
        "eslint": "^8.32.0",
        "eslint-config-prettier": "^8.6.0",
        "eslint-config-xo": "^0.43.1",
        "eslint-config-xo-typescript": "^0.55.1",
        "eslint-plugin-react": "^7.32.1",
        "opener": "^1.5.2",
        "typescript": "^4.9.4",
        "vite": "^4.0.0"
    }

Update: If I disable those rules and take out the typing, things do render as I'd expect.

/* eslint-disable @typescript-eslint/no-unsafe-assignment */
//...
const routes: RouteObject[] = [
    {
        path: '/',
        element: (
            <div>
                <a href="./test">test</a>
            </div>
        ),
    },
    { path: '/test', element: <div>hello</div> },
];

// eslint-disable-next-line @typescript-eslint/no-unsafe-call
const myRouter = createBrowserRouter(routes);

ReactDOM.createRoot(document.getElementById('root')!).render(
    <React.StrictMode>
        <RouterProvider router={myRouter} />
    </React.StrictMode>
);

react-router@6 and react-router-dom@6 are completely written in Typescript, so there is no need to import external typings. The v5 typings are likely messing with your build step.

You should uninstall @types/react-router and @types/react-router-dom .

npm uninstall --save @types/react-router
npm uninstall --save @types/react-router-dom

From here I don't believe you'll need to explicitly type the data router. The return type from createBrowserRouter is RemixRouter , not BrowserRouter .

import React from 'react';
import ReactDOM from 'react-dom/client';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import AnItem from './components/Shared/AnItem';

const myRouter = createBrowserRouter([
  {
    path: '/',
    element: <AnItem />,
  },
]);

ReactDOM.createRoot(document.getElementById('root')!)
  .render(
    <React.StrictMode>
      <RouterProvider router={myRouter} />
    </React.StrictMode>
  );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM