New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Strengthen route typings #9366
Changes from 14 commits
56022e7
4c331d0
093a5c0
d3cdf1a
c7e50a1
e0903d5
8b6d8ed
e4cc495
5f2a196
7622a69
7b7090e
7cbacec
070abd4
ac23968
6d72e41
7bee9dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,7 @@ | |
- goldins | ||
- gowthamvbhat | ||
- GraxMonzo | ||
- GuptaSiddhant | ||
- haivuw | ||
- hernanif1 | ||
- hongji00 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,6 @@ | ||
import * as React from "react"; | ||
import type { | ||
TrackedPromise, | ||
HydrationState, | ||
InitialEntry, | ||
Location, | ||
MemoryHistory, | ||
|
@@ -22,9 +21,11 @@ import { useSyncExternalStore as useSyncExternalStoreShim } from "./use-sync-ext | |
|
||
import type { | ||
DataRouteObject, | ||
IndexRouteObject, | ||
RouteMatch, | ||
RouteObject, | ||
Navigator, | ||
NonIndexRouteObject, | ||
RelativeRoutingType, | ||
} from "./context"; | ||
import { | ||
|
@@ -220,49 +221,26 @@ export function Outlet(props: OutletProps): React.ReactElement | null { | |
return useOutlet(props.context); | ||
} | ||
|
||
interface DataRouteProps { | ||
id?: RouteObject["id"]; | ||
loader?: RouteObject["loader"]; | ||
action?: RouteObject["action"]; | ||
errorElement?: RouteObject["errorElement"]; | ||
shouldRevalidate?: RouteObject["shouldRevalidate"]; | ||
handle?: RouteObject["handle"]; | ||
} | ||
|
||
export interface RouteProps extends DataRouteProps { | ||
caseSensitive?: boolean; | ||
export type PathRouteProps = Omit<NonIndexRouteObject, "children"> & { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a nit here: but I much prefer to avoid using |
||
children?: React.ReactNode; | ||
element?: React.ReactNode | null; | ||
index?: boolean; | ||
path?: string; | ||
} | ||
}; | ||
|
||
export interface PathRouteProps extends DataRouteProps { | ||
caseSensitive?: boolean; | ||
export type LayoutRouteProps = Omit<NonIndexRouteObject, "children"> & { | ||
children?: React.ReactNode; | ||
element?: React.ReactNode | null; | ||
index?: false; | ||
path: string; | ||
} | ||
}; | ||
|
||
export interface LayoutRouteProps extends DataRouteProps { | ||
children?: React.ReactNode; | ||
element?: React.ReactNode | null; | ||
} | ||
export type IndexRouteProps = Omit<IndexRouteObject, "children"> & { | ||
children?: undefined; | ||
}; | ||
|
||
export interface IndexRouteProps extends DataRouteProps { | ||
element?: React.ReactNode | null; | ||
index: true; | ||
} | ||
export type RouteProps = PathRouteProps | LayoutRouteProps | IndexRouteProps; | ||
|
||
/** | ||
* Declares an element that should be rendered at a certain URL path. | ||
* | ||
* @see https://reactrouter.com/docs/en/v6/components/route | ||
*/ | ||
export function Route( | ||
_props: PathRouteProps | LayoutRouteProps | IndexRouteProps | ||
): React.ReactElement | null { | ||
export function Route(_props: RouteProps): React.ReactElement | null { | ||
invariant( | ||
false, | ||
`A <Route> is only ever to be used as the child of <Routes> element, ` + | ||
|
@@ -569,6 +547,11 @@ export function createRoutesFromChildren( | |
}] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>` | ||
); | ||
|
||
invariant( | ||
!element.props.index || !element.props.children, | ||
"An index route cannot have child routes." | ||
); | ||
|
||
let treePath = [...parentPath, index]; | ||
let route: RouteObject = { | ||
id: element.props.id || treePath.join("-"), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,39 @@ | ||
import * as React from "react"; | ||
import type { | ||
TrackedPromise, | ||
AgnosticRouteMatch, | ||
AgnosticIndexRouteObject, | ||
AgnosticNonIndexRouteObject, | ||
History, | ||
Location, | ||
Router, | ||
StaticHandlerContext, | ||
To, | ||
AgnosticRouteObject, | ||
AgnosticRouteMatch, | ||
TrackedPromise, | ||
} from "@remix-run/router"; | ||
import type { Action as NavigationType } from "@remix-run/router"; | ||
|
||
// Create react-specific types from the agnostic types in @remix-run/router to | ||
// export from react-router | ||
export interface RouteObject extends AgnosticRouteObject { | ||
export type IndexRouteObject = Omit<AgnosticIndexRouteObject, "children"> & { | ||
children?: undefined; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why |
||
element?: React.ReactNode | null; | ||
errorElement?: React.ReactNode | null; | ||
}; | ||
export type NonIndexRouteObject = Omit< | ||
AgnosticNonIndexRouteObject, | ||
"children" | ||
> & { | ||
children?: RouteObject[]; | ||
element?: React.ReactNode | null; | ||
errorElement?: React.ReactNode | null; | ||
} | ||
}; | ||
|
||
export interface DataRouteObject extends RouteObject { | ||
export type RouteObject = IndexRouteObject | NonIndexRouteObject; | ||
|
||
export type DataRouteObject = RouteObject & { | ||
children?: DataRouteObject[]; | ||
id: string; | ||
} | ||
}; | ||
|
||
export interface RouteMatch< | ||
ParamKey extends string = string, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got rid of the duplication here -
<Route>
props are now justRouteObject
equivalents that expectReactNode
children instead ofReactElement
children