Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
697 views
in Technique[技术] by (71.8m points)

reactjs - React Typescript: How to type location in react-router-dom

I have a routing like this:

<BrowserRouter>
  <PageRouting >
    <Route exact component={DashboardPage} path={routes.ROUTE_MAIN} />
    <Route component={DocumentsPage} path={routes.ROUTE_DOCUMENTS} />
    <Route component={SettingsPage} path={routes.ROUTE_SETTINGS} />
  </PageRouting>
  <Redirect to={routes.ROUTE_MAIN} />
</BrowserRouter>

Routes are literal types:

const routes = {
  ROUTE_MAIN: '/',
  ROUTE_DASHBOARD: '/',
  ROUTE_DOCUMENTS: '/documents',
  ROUTE_SETTINGS: '/settings',
}

I want my location with type:

type routesKeys = keyof typeof routes

type LocationTypes {
  pathname: routesKeys
}

const location = useLocation<LocationTypes>()

But 'location.pathname' is a type of string, not 'routesKeys'.

How can I set type for location.pathname?

EDIT:

'location.pathname' should be a type of:

type routesPaths = typeof routes[routesKeys]
question from:https://stackoverflow.com/questions/66064044/react-typescript-how-to-type-location-in-react-router-dom

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

There's not a way to do this just by passing types to useLocation. The generic on useLocation, which you are setting to LocationTypes, actually refers to the property location.state. location.pathname is always just a string.

You would have to either extends the typings of these packages or assert correctness via as.

I don't have a ton of experience extending packages, so I don't know how to make this work correctly. I think you can only extend an interface and not a type? Maybe someone else knows.

declare module 'history' {
    export type Pathname = keyof typeof routes;
}

The assertion approach is basically wrapping the built-in function with your own.

import {useLocation as useLocationImported} from "react-router-dom";
import {State, Location} from "history";

export const useLocation = <S extends State = State>() => 
    useLocationImported<S>() as Location<S> & {pathname: routesKeys}
const location = useLocation();
const path = location.pathname; // type is "ROUTE_MAIN" | "ROUTE_DASHBOARD" | "ROUTE_DOCUMENTS" | "ROUTE_SETTINGS"

Edit: on further thought, I don't think you want to do this. These sort of typings make it so that the path is always an exact match to one of your routes, but in reality that's not the case 100% of the time. You will create problems if you assume that it is.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...