From a4c4637f4ab10408d69b7221d629fc6b076f4bd1 Mon Sep 17 00:00:00 2001 From: Brian Chen Date: Mon, 7 Mar 2022 07:28:20 +1100 Subject: [PATCH] [react-router-dom] Add v6 (#4278) * copy from v5 * add some of the funcs from react-rotuer * fix the tests * add some tests * add funcs added --- .../flow_v0.104.x-/react-router-dom_v6.x.x.js | 292 +++++++++++ .../flow_v0.104.x-/test_react-router-dom.js | 462 ++++++++++++++++++ .../react-router-dom_v6.x.x.js | 168 +++++++ .../test_react-router-dom.js | 380 ++++++++++++++ .../react-router-dom_v6.x.x.js | 170 +++++++ .../test_react-router-dom.js | 380 ++++++++++++++ 6 files changed, 1852 insertions(+) create mode 100644 definitions/npm/react-router-dom_v6.x.x/flow_v0.104.x-/react-router-dom_v6.x.x.js create mode 100644 definitions/npm/react-router-dom_v6.x.x/flow_v0.104.x-/test_react-router-dom.js create mode 100644 definitions/npm/react-router-dom_v6.x.x/flow_v0.63.x-v0.97.x/react-router-dom_v6.x.x.js create mode 100644 definitions/npm/react-router-dom_v6.x.x/flow_v0.63.x-v0.97.x/test_react-router-dom.js create mode 100644 definitions/npm/react-router-dom_v6.x.x/flow_v0.98.x-v0.103.x/react-router-dom_v6.x.x.js create mode 100644 definitions/npm/react-router-dom_v6.x.x/flow_v0.98.x-v0.103.x/test_react-router-dom.js diff --git a/definitions/npm/react-router-dom_v6.x.x/flow_v0.104.x-/react-router-dom_v6.x.x.js b/definitions/npm/react-router-dom_v6.x.x/flow_v0.104.x-/react-router-dom_v6.x.x.js new file mode 100644 index 0000000000..cef2452685 --- /dev/null +++ b/definitions/npm/react-router-dom_v6.x.x/flow_v0.104.x-/react-router-dom_v6.x.x.js @@ -0,0 +1,292 @@ +declare module "react-router-dom" { + declare export var BrowserRouter: React$ComponentType<{| + basename?: string, + forceRefresh?: boolean, + getUserConfirmation?: GetUserConfirmation, + keyLength?: number, + children?: React$Node + |}> + + declare export var HashRouter: React$ComponentType<{| + basename?: string, + getUserConfirmation?: GetUserConfirmation, + hashType?: "slash" | "noslash" | "hashbang", + children?: React$Node + |}> + + declare export var Link: React$ComponentType<{ + +className?: string, + +to: string | LocationShape, + +replace?: boolean, + +children?: React$Node, + ... + }> + + declare export var NavLink: React$ComponentType<{ + +to: string | LocationShape, + +activeClassName?: string, + +className?: string, + +activeStyle?: { +[string]: mixed, ... }, + +style?: { +[string]: mixed, ... }, + +isActive?: (match: Match, location: Location) => boolean, + +children?: React$Node, + +exact?: boolean, + +strict?: boolean, + ... + }> + + // NOTE: Below are duplicated from react-router. If updating these, please + // update the react-router and react-router-native types as well. + declare export type Location = $ReadOnly<{ + pathname: string, + search: string, + hash: string, + state?: any, + key?: string, + ... + }>; + + declare export type LocationShape = { + pathname?: string, + search?: string, + hash?: string, + state?: any, + ... + }; + + declare export type HistoryAction = "PUSH" | "REPLACE" | "POP"; + + declare export type RouterHistory = { + length: number, + location: Location, + action: HistoryAction, + listen( + callback: (location: Location, action: HistoryAction) => void + ): () => void, + push(path: string | LocationShape, state?: any): void, + replace(path: string | LocationShape, state?: any): void, + go(n: number): void, + goBack(): void, + goForward(): void, + canGo?: (n: number) => boolean, + block( + callback: string | (location: Location, action: HistoryAction) => ?string + ): () => void, + ... + }; + + declare export type Match = { + params: { [key: string]: ?string, ... }, + isExact: boolean, + path: string, + url: string, + ... + }; + + declare export type ContextRouter = {| + history: RouterHistory, + location: Location, + match: Match, + staticContext?: StaticRouterContext + |}; + + declare type ContextRouterVoid = { + history: RouterHistory | void, + location: Location | void, + match: Match | void, + staticContext?: StaticRouterContext | void, + ... + }; + + declare export type GetUserConfirmation = ( + message: string, + callback: (confirmed: boolean) => void + ) => void; + + declare export type StaticRouterContext = { url?: string, ... }; + + declare export var StaticRouter: React$ComponentType<{| + basename?: string, + location?: string | Location, + context: StaticRouterContext, + children?: React$Node + |}> + + declare export var MemoryRouter: React$ComponentType<{| + initialEntries?: Array, + initialIndex?: number, + getUserConfirmation?: GetUserConfirmation, + keyLength?: number, + children?: React$Node + |}> + + declare export var Router: React$ComponentType<{| + history: RouterHistory, + children?: React$Node + |}> + + declare export var Route: React$ComponentType<{| + caseSensitive?: boolean, + children?: React$Node, + element?: React$Element | null, + index?: boolean, + path?: string, + |}> + + declare export var Prompt: React$ComponentType<{| + message: string | ((location: Location) => string | boolean), + when?: boolean + |}> + + declare export var Outlet: React$ComponentType<{| + context?: mixed; + |}> + + declare export var Redirect: React$ComponentType<{| + to: string | LocationShape, + push?: boolean, + from?: string, + exact?: boolean, + strict?: boolean + |}> + + declare export var Route: React$ComponentType<{| + caseSensitive?: boolean, + children?: React$Node, + element?: React$Element | null, + index?: boolean, + path?: string, + |}> + + declare export var Routes: React$ComponentType<{| + children?: React$Node, + location?: Location + |}> + + declare export function withRouter>( + WrappedComponent: Component + ): React$ComponentType<$Diff, ContextRouterVoid>>; + + declare type MatchPathOptions = { + path?: string | string[], + exact?: boolean, + sensitive?: boolean, + strict?: boolean, + ... + }; + + declare export function matchPath( + pathname: string, + options?: MatchPathOptions | string | string[], + parent?: Match + ): null | Match; + + declare export function useHistory(): $PropertyType; + declare export function useLocation(): $PropertyType; + declare export function useOutletContext(): T; + declare export function useParams, 'params'>>(): Params; + declare export function useRouteMatch(path?: MatchPathOptions | string | string[]): $PropertyType; + + declare export function generatePath(pattern?: string, params?: { +[string]: mixed, ... }): string; + + declare type RouteObject = {| + caseSensitive?: boolean, + children?: Array, + element?: React$Node, + index?: boolean, + path?: string, + |}; + + declare export function createRoutesFromChildren( + children: React$Node, + ): Array; + + declare type Params = { + +[key: Key]: string | void; + }; + + declare type RouteMatch = {| + params: Params, + pathname: string, + route: RouteObject, + |}; + + declare export function matchRoutes( + routes: Array, + location: LocationShape | string, + basename?: string, + ): Array> | null; + + declare export function renderMatches( + matches: Array> | null, + ): React$Element | null; + + declare type PathPattern = {| + path: string, + caseSensitive?: boolean, + end?: boolean, + |}; + + declare type PathMatch = {| + params: Params, + pathname: string, + pattern: PathPattern, + |}; + + declare export function matchPath( + pattern: PathPattern | string, + pathname: string, + ): PathMatch | null; + + declare type To = LocationShape | string; + + declare type Path = {| + pathname: string, + search: string, + hash: string, + |}; + + declare export function resolvePath( + to: To, + fromPathname?: string + ): Path; + + declare export function useHref(to: To): string; + + declare export function useInRouterContext(): boolean; + + declare export function useNavigationType(): 'POP' | 'PUSH' | 'REPLACE'; + + declare export function useMatch( + pattern: PathPattern | string + ): PathMatch | null; + + declare export function useOutlet(): React$Element | null; + + declare export function useRoutes( + routes: Array, + location?: LocationShape | string, + ): React$Element | null; + + declare export function useSearchParams( + defaultInit?: URLSearchParamsInit + ): [URLSearchParams, SetURLSearchParams]; + + declare type URLSearchParamsInit = + | string + | Array<[string, string]> + | { [key: string]: string | Array, ... } + | URLSearchParams; + + declare type SetURLSearchParams = ( + nextInit?: URLSearchParamsInit, + navigateOpts?: {| + replace?: boolean, + state?: any, + |} + ) => void; + + declare export function createSearchParams( + init?: URLSearchParamsInit, + ): URLSearchParams; +} diff --git a/definitions/npm/react-router-dom_v6.x.x/flow_v0.104.x-/test_react-router-dom.js b/definitions/npm/react-router-dom_v6.x.x/flow_v0.104.x-/test_react-router-dom.js new file mode 100644 index 0000000000..3722188b6d --- /dev/null +++ b/definitions/npm/react-router-dom_v6.x.x/flow_v0.104.x-/test_react-router-dom.js @@ -0,0 +1,462 @@ +// @flow +import React from "react"; +import { + BrowserRouter, + HashRouter, + Link, + NavLink, + matchPath, + withRouter, + Outlet, + Redirect, + Route, + Routes, + useHistory, + useLocation, + useOutletContext, + useParams, + useRouteMatch, +} from "react-router-dom"; +import type { + Location, + ContextRouter, + Match, + StaticRouterContext, + RouterHistory, +} from "react-router-dom"; +import { it, describe } from "flow-typed-test"; + +describe("react-router-dom", () => { + describe("BrowserRouter", () => { + it("works", () => { + +
+ ; + + {}} + keyLength={3} + > +
+ ; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[incompatible-type] - basename must be a string + ; + }); + }); + + describe("HashRouter", () => { + it("works", () => { + +
+ ; + + {}} + hashType="noslash" + > +
+ ; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[incompatible-type] - hashType must be a string + ; + }); + }); + + describe("", () => { + it("works", () => { + About; + + + About + ; + + + About + ; + }); + + it("allows attributes of element", () => { + {}} + >About; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[prop-missing] - to prop is required + ; + + // $FlowExpectedError[incompatible-type] - to prop must be a string or LocationShape + ; + }); + }); + + describe("", () => { + it("works", () => { + About; + + true} + strict + exact + > + About + ; + + + About + ; + }); + + it("allows attributes of element", () => { + {}} + >About; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[prop-missing] - to prop is required + ; + + // $FlowExpectedError[incompatible-type] - to prop must be a string or LocationShape + ; + }); + }); + + describe("matchPath", () => { + it("works", () => { + const match: null | Match = matchPath("/the/pathname", { + path: "/the/:dynamicId", + exact: true, + strict: false + }); + const match2: null | Match = matchPath("/the/pathname", { + path: ["/the/:dynamicId", "/the/otherRoute"], + exact: true, + strict: false, + }); + const match3: null | Match = matchPath("/the/pathname", "/the/:dynamicId"); + const match4: null | Match = matchPath("/the/pathname", [ + "/the/:dynamicId", + "/the/otherRoute", + ]); + const match5: null | Match = matchPath("/the/pathname"); + }); + + it("raises an error if passed invalid argument", () => { + // $FlowExpectedError[incompatible-call] - pathname argument is required + matchPath(); + + // $FlowExpectedError[incompatible-type] - matchPath returns Match or null + const matchError: string = matchPath("/the/pathname", { + path: "the/:dynamicId" + }); + }); + }); + + describe("withRouter", () => { + type Props = { + history: RouterHistory, + location: Location, + match: Match, + staticContext: StaticRouterContext, + s: string, + ... + }; + describe("Stateless Functional Components", () => { + it("passes if the component is passed required props", () => { + const Comp = ({ + history, + location, + match, + staticContext, + s + }: Props) =>
; + const WrappedComp = withRouter(Comp); + ; + + const ChainedHOC = withRouter(WrappedComp); + ; + }); + + it("errors if the component is not passed correct props", () => { + const Comp = ({ + history, + location, + match, + staticContext, + s + }: Props) =>
; + const WrappedComp = withRouter(Comp); + // $FlowExpectedError[prop-missing] - missing prop "s" + ; + // $FlowExpectedError[incompatible-type] - wrong type + ; + + const ChainedHOC = withRouter(WrappedComp); + // $FlowExpectedError[prop-missing] - missing prop "s" + ; + // $FlowExpectedError[incompatible-type] - wrong type + ; + }); + + it("errors if trying to access a prop that withRouter does not supply", () => { + const Comp = ({ histry, s }: { + histry: RouterHistory, + s: string, + ... + }) => ( +
+ ); + const WrappedComp = withRouter(Comp); + }); + + it("errors if using block() incorrectly", () => { + const Comp = ({history}: { history: RouterHistory, ... }) => { + // $FlowExpectedError[incompatible-call] - wrong param + history.block(false); + + // These are valid + history.block('Are you sure you want to leave this page?'); + history.block((location, action) => { + return 'Are you sure you want to leave this page?'; + }); + + return
; + }; + const WrappedComp = withRouter(Comp); + }); + }); + + describe("Class Components", () => { + it("passes if the component is passed required props", () => { + class Comp extends React.Component { + render() { + return
; + } + } + const WrappedComp = withRouter(Comp); + ; + + const ChainedHOC = withRouter(WrappedComp); + ; + }); + + it("errors if the component is not passed the correct props", () => { + class Comp extends React.Component { + render() { + return
; + } + } + const WrappedComp = withRouter(Comp); + // $FlowExpectedError[prop-missing] - missing prop "s" + ; + // $FlowExpectedError[incompatible-type] - wrong type + ; + + const ChainedHOC = withRouter(WrappedComp); + // $FlowExpectedError[prop-missing] - missing prop "s" + ; + // $FlowExpectedError[incompatible-type] - wrong type + ; + }); + + it("passes if a required prop is handled by defaultProps", () => { + class Comp extends React.Component { + static defaultProps = { + s: "defaultS" + }; + render() { + return
; + } + } + const WrappedComp = withRouter(Comp); + ; + ; + + const ChainedHOC = withRouter(WrappedComp); + ; + ; + }); + + it("errors if a required prop that has a defaultProp is passed the wrong type", () => { + class Comp extends React.Component { + static defaultProps = { + s: "defaultS" + }; + render() { + return
; + } + } + const WrappedComp = withRouter(Comp); + // $FlowExpectedError[incompatible-type] - wrong type + ; + + const ChainedHOC = withRouter(WrappedComp); + // $FlowExpectedError[incompatible-type] - wrong type + ; + }); + }); + }); + + describe("Redirect", () => { + it("works", () => { + ; + + ; + + ; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[prop-missing] - to prop is required + ; + + // $FlowExpectedError[incompatible-type] - to prop must be a string or LocationShape + ; + + // $FlowExpectedError[prop-missing] - unexpected prop xxx + ; + }); + }); + + describe("Route", () => { + it("works", () => { + const Component = ({}) =>
Hi!
; + ; + + } />; + + ; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[incompatible-type] - prop must be a string + ; + + // $FlowExpectedError[prop-missing] - unexpected prop xxx + ; + }); + }); + + describe('Routes', () => { + it('works', () => { + const Component = ({}) =>
Hi!
; + + } /> + ; + }); + }); + + describe('Outlet', () => { + it('can be used alone', () => { + ; + }); + + it('can be passed anything', () => { + const [count, setCount] = React.useState(0); + ; + }); + }); + + describe('react hook', () => { + it('useHistory', () => { + const history: RouterHistory = useHistory(); + }); + + it('useLocation', () => { + const location: Location = useLocation(); + }); + + it('useOutlet', () => { + const [count, setCount] = useOutletContext(); + const increment = () => setCount((c) => c + 1); + ; + + // $FlowExpectedError[extra-arg] + useOutletContext(''); + }); + + it('useParams', () => { + const params: { [key: string]: ?string, ... } = useParams(); + }); + + it('useParams with generic', () => { + type ParamsType = {| + +slug: string, + |}; + + const params: ParamsType = useParams(); + }); + + it('useRouteMatch', () => { + const match: Match = useRouteMatch(); + const matchPath: Match = useRouteMatch('/path'); + const matchArray: Match = useRouteMatch(['/path', '/the/otherRoute']); + + const matchObject: Match = useRouteMatch({ + path: '/path', + strict: true, + sensitive: true, + exact: true, + }); + + // $FlowExpectedError[incompatible-call] + const matchObject2: Match = useRouteMatch({ + sensitive: 'foo', + }); + }); + }); +}); diff --git a/definitions/npm/react-router-dom_v6.x.x/flow_v0.63.x-v0.97.x/react-router-dom_v6.x.x.js b/definitions/npm/react-router-dom_v6.x.x/flow_v0.63.x-v0.97.x/react-router-dom_v6.x.x.js new file mode 100644 index 0000000000..29b206e639 --- /dev/null +++ b/definitions/npm/react-router-dom_v6.x.x/flow_v0.63.x-v0.97.x/react-router-dom_v6.x.x.js @@ -0,0 +1,168 @@ +declare module "react-router-dom" { + declare export var BrowserRouter: React$ComponentType<{| + basename?: string, + forceRefresh?: boolean, + getUserConfirmation?: GetUserConfirmation, + keyLength?: number, + children?: React$Node + |}> + + declare export var HashRouter: React$ComponentType<{| + basename?: string, + getUserConfirmation?: GetUserConfirmation, + hashType?: "slash" | "noslash" | "hashbang", + children?: React$Node + |}> + + declare export var Link: React$ComponentType<{ + className?: string, + to: string | LocationShape, + replace?: boolean, + children?: React$Node + }> + + declare export var NavLink: React$ComponentType<{ + to: string | LocationShape, + activeClassName?: string, + className?: string, + activeStyle?: { +[string]: mixed }, + style?: { +[string]: mixed }, + isActive?: (match: Match, location: Location) => boolean, + children?: React$Node, + exact?: boolean, + strict?: boolean + }> + + // NOTE: Below are duplicated from react-router. If updating these, please + // update the react-router and react-router-native types as well. + declare export type Location = { + pathname: string, + search: string, + hash: string, + state?: any, + key?: string + }; + + declare export type LocationShape = { + pathname?: string, + search?: string, + hash?: string, + state?: any + }; + + declare export type HistoryAction = "PUSH" | "REPLACE" | "POP"; + + declare export type RouterHistory = { + length: number, + location: Location, + action: HistoryAction, + listen( + callback: (location: Location, action: HistoryAction) => void + ): () => void, + push(path: string | LocationShape, state?: any): void, + replace(path: string | LocationShape, state?: any): void, + go(n: number): void, + goBack(): void, + goForward(): void, + canGo?: (n: number) => boolean, + block( + callback: string | (location: Location, action: HistoryAction) => ?string + ): () => void, + // createMemoryHistory + index?: number, + entries?: Array + }; + + declare export type Match = { + params: { [key: string]: ?string }, + isExact: boolean, + path: string, + url: string + }; + + declare export type ContextRouter = {| + history: RouterHistory, + location: Location, + match: Match, + staticContext?: StaticRouterContext + |}; + + declare type ContextRouterVoid = { + history: RouterHistory | void, + location: Location | void, + match: Match | void, + staticContext?: StaticRouterContext | void + }; + + declare export type GetUserConfirmation = ( + message: string, + callback: (confirmed: boolean) => void + ) => void; + + declare export type StaticRouterContext = { + url?: string + }; + + declare export var StaticRouter: React$ComponentType<{| + basename?: string, + location?: string | Location, + context: StaticRouterContext, + children?: React$Node + |}> + + declare export var MemoryRouter: React$ComponentType<{| + initialEntries?: Array, + initialIndex?: number, + getUserConfirmation?: GetUserConfirmation, + keyLength?: number, + children?: React$Node + |}> + + declare export var Router: React$ComponentType<{| + history: RouterHistory, + children?: React$Node + |}> + + declare export var Prompt: React$ComponentType<{| + message: string | ((location: Location) => string | boolean), + when?: boolean + |}> + + declare export var Redirect: React$ComponentType<{| + to: string | LocationShape, + push?: boolean, + from?: string, + exact?: boolean, + strict?: boolean + |}> + + declare export var Route: React$ComponentType<{| + caseSensitive?: boolean, + children?: React$Node, + element?: React$Element | null, + index?: boolean, + path?: string, + |}> + + declare export var Routes: React$ComponentType<{| + children?: React$Node, + location?: Location + |}> + + declare export function withRouter>(WrappedComponent: Component) : React$ComponentType<$Diff>, ContextRouterVoid>>; + + declare type MatchPathOptions = { + path?: string | string[], + exact?: boolean, + sensitive?: boolean, + strict?: boolean + }; + + declare export function matchPath( + pathname: string, + options?: MatchPathOptions | string | string[], + parent?: Match + ): null | Match; + + declare export function generatePath(pattern?: string, params?: { +[string]: mixed }): string; +} diff --git a/definitions/npm/react-router-dom_v6.x.x/flow_v0.63.x-v0.97.x/test_react-router-dom.js b/definitions/npm/react-router-dom_v6.x.x/flow_v0.63.x-v0.97.x/test_react-router-dom.js new file mode 100644 index 0000000000..9c4a70f177 --- /dev/null +++ b/definitions/npm/react-router-dom_v6.x.x/flow_v0.63.x-v0.97.x/test_react-router-dom.js @@ -0,0 +1,380 @@ +// @flow +import React from "react"; +import { + BrowserRouter, + HashRouter, + Link, + NavLink, + matchPath, + withRouter, + Redirect, + Route +} from "react-router-dom"; +import type { + ContextRouter, + Match, + StaticRouterContext, + RouterHistory +} from "react-router-dom"; +import { it, describe } from "flow-typed-test"; + +describe("react-router-dom", () => { + describe("BrowserRouter", () => { + it("works", () => { + +
+ ; + + {}} + keyLength={3} + > +
+ ; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[incompatible-type] - basename must be a string + ; + }); + }); + + describe("HashRouter", () => { + it("works", () => { + +
+ ; + + {}} + hashType="noslash" + > +
+ ; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[incompatible-type] - hashType must be a string + ; + }); + }); + + describe("", () => { + it("works", () => { + About; + + + About + ; + + + About + ; + }); + + it("allows attributes of element", () => { + {}} + >About; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[prop-missing] - to prop is required + ; + + // $FlowExpectedError[incompatible-type] - to prop must be a string or LocationShape + ; + }); + }); + + describe("", () => { + it("works", () => { + About; + + true} + strict + exact + > + About + ; + + + About + ; + }); + + it("allows attributes of element", () => { + {}} + >About; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[prop-missing] - to prop is required + ; + + // $FlowExpectedError[incompatible-type] - to prop must be a string or LocationShape + ; + }); + }); + + describe("matchPath", () => { + it("works", () => { + const match: null | Match = matchPath("/the/pathname", { + path: "/the/:dynamicId", + exact: true, + strict: false + }); + const match2: null | Match = matchPath("/the/pathname", { + path: ["/the/:dynamicId", "/the/otherRoute"], + exact: true, + strict: false, + }); + const match3: null | Match = matchPath("/the/pathname", "/the/:dynamicId"); + const match4: null | Match = matchPath("/the/pathname", [ + "/the/:dynamicId", + "/the/otherRoute", + ]); + const match5: null | Match = matchPath("/the/pathname"); + }); + + it("raises an error if passed invalid argument", () => { + // $FlowExpectedError[incompatible-call] - pathname argument is required + matchPath(); + + // $FlowExpectedError[incompatible-type] - matchPath returns Match or null + const matchError: string = matchPath("/the/pathname", { + path: "the/:dynamicId" + }); + }); + }); + + describe("withRouter", () => { + type Props = { + history: RouterHistory, + location: Location, + match: Match, + staticContext: StaticRouterContext, + s: string + }; + describe("Stateless Functional Components", () => { + it("passes if the component is passed required props", () => { + const Comp = ({ + history, + location, + match, + staticContext, + s + }: Props) =>
; + const WrappedComp = withRouter(Comp); + ; + + const ChainedHOC = withRouter(WrappedComp); + ; + }); + + it("errors if the component is not passed correct props", () => { + const Comp = ({ + history, + location, + match, + staticContext, + s + }: Props) =>
; + const WrappedComp = withRouter(Comp); + // $FlowExpectedError[prop-missing] - missing prop "s" + ; + // $FlowExpectedError[incompatible-type] - wrong type + ; + + const ChainedHOC = withRouter(WrappedComp); + // $FlowExpectedError[prop-missing] - missing prop "s" + ; + // $FlowExpectedError[incompatible-type] - wrong type + ; + }); + + it("errors if trying to access a prop that withRouter does not supply", () => { + const Comp = ({ histry, s }: { histry: RouterHistory, s: string }) => ( +
+ ); + const WrappedComp = withRouter(Comp); + }); + + it("errors if using block() incorrectly", () => { + const Comp = ({history}: {history: RouterHistory}) => { + // $FlowExpectedError[incompatible-call] - wrong param + history.block(false); + + // These are valid + history.block('Are you sure you want to leave this page?'); + history.block((location, action) => { + return 'Are you sure you want to leave this page?'; + }); + + return
; + }; + const WrappedComp = withRouter(Comp); + }); + }); + + describe("Class Components", () => { + it("passes if the component is passed required props", () => { + class Comp extends React.Component { + render() { + return
; + } + } + const WrappedComp = withRouter(Comp); + ; + + const ChainedHOC = withRouter(WrappedComp); + ; + }); + + it("errors if the component is not passed the correct props", () => { + class Comp extends React.Component { + render() { + return
; + } + } + const WrappedComp = withRouter(Comp); + // $FlowExpectedError[prop-missing] - missing prop "s" + ; + // $FlowExpectedError[incompatible-type] - wrong type + ; + + const ChainedHOC = withRouter(WrappedComp); + // $FlowExpectedError[prop-missing] - missing prop "s" + ; + // $FlowExpectedError[incompatible-type] - wrong type + ; + }); + + it("passes if a required prop is handled by defaultProps", () => { + class Comp extends React.Component { + static defaultProps = { + s: "defaultS" + }; + render() { + return
; + } + } + const WrappedComp = withRouter(Comp); + ; + ; + + const ChainedHOC = withRouter(WrappedComp); + ; + ; + }); + + it("errors if a required prop that has a defaultProp is passed the wrong type", () => { + class Comp extends React.Component { + static defaultProps = { + s: "defaultS" + }; + render() { + return
; + } + } + const WrappedComp = withRouter(Comp); + // $FlowExpectedError[incompatible-type] - wrong type + ; + + const ChainedHOC = withRouter(WrappedComp); + // $FlowExpectedError[incompatible-type] - wrong type + ; + }); + }); + }); + + describe("Redirect", () => { + it("works", () => { + ; + + ; + + ; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[prop-missing] - to prop is required + ; + + // $FlowExpectedError[incompatible-type] - to prop must be a string or LocationShape + ; + + // $FlowExpectedError[prop-missing] - unexpected prop xxx + ; + }); + }); + + describe("Route", () => { + it("works", () => { + const Component = ({}) =>
Hi!
; + ; + + } />; + + ; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[incompatible-type] - prop must be a string + ; + + // $FlowExpectedError[prop-missing] - unexpected prop xxx + ; + }); + }) +}); diff --git a/definitions/npm/react-router-dom_v6.x.x/flow_v0.98.x-v0.103.x/react-router-dom_v6.x.x.js b/definitions/npm/react-router-dom_v6.x.x/flow_v0.98.x-v0.103.x/react-router-dom_v6.x.x.js new file mode 100644 index 0000000000..ad1a75f9e0 --- /dev/null +++ b/definitions/npm/react-router-dom_v6.x.x/flow_v0.98.x-v0.103.x/react-router-dom_v6.x.x.js @@ -0,0 +1,170 @@ +declare module "react-router-dom" { + declare export var BrowserRouter: React$ComponentType<{| + basename?: string, + forceRefresh?: boolean, + getUserConfirmation?: GetUserConfirmation, + keyLength?: number, + children?: React$Node + |}> + + declare export var HashRouter: React$ComponentType<{| + basename?: string, + getUserConfirmation?: GetUserConfirmation, + hashType?: "slash" | "noslash" | "hashbang", + children?: React$Node + |}> + + declare export var Link: React$ComponentType<{ + className?: string, + to: string | LocationShape, + replace?: boolean, + children?: React$Node + }> + + declare export var NavLink: React$ComponentType<{ + to: string | LocationShape, + activeClassName?: string, + className?: string, + activeStyle?: { +[string]: mixed }, + style?: { +[string]: mixed }, + isActive?: (match: Match, location: Location) => boolean, + children?: React$Node, + exact?: boolean, + strict?: boolean + }> + + // NOTE: Below are duplicated from react-router. If updating these, please + // update the react-router and react-router-native types as well. + declare export type Location = { + pathname: string, + search: string, + hash: string, + state?: any, + key?: string + }; + + declare export type LocationShape = { + pathname?: string, + search?: string, + hash?: string, + state?: any + }; + + declare export type HistoryAction = "PUSH" | "REPLACE" | "POP"; + + declare export type RouterHistory = { + length: number, + location: Location, + action: HistoryAction, + listen( + callback: (location: Location, action: HistoryAction) => void + ): () => void, + push(path: string | LocationShape, state?: any): void, + replace(path: string | LocationShape, state?: any): void, + go(n: number): void, + goBack(): void, + goForward(): void, + canGo?: (n: number) => boolean, + block( + callback: string | (location: Location, action: HistoryAction) => ?string + ): () => void, + // createMemoryHistory + index?: number, + entries?: Array + }; + + declare export type Match = { + params: { [key: string]: ?string }, + isExact: boolean, + path: string, + url: string + }; + + declare export type ContextRouter = {| + history: RouterHistory, + location: Location, + match: Match, + staticContext?: StaticRouterContext + |}; + + declare type ContextRouterVoid = { + history: RouterHistory | void, + location: Location | void, + match: Match | void, + staticContext?: StaticRouterContext | void + }; + + declare export type GetUserConfirmation = ( + message: string, + callback: (confirmed: boolean) => void + ) => void; + + declare export type StaticRouterContext = { + url?: string + }; + + declare export var StaticRouter: React$ComponentType<{| + basename?: string, + location?: string | Location, + context: StaticRouterContext, + children?: React$Node + |}> + + declare export var MemoryRouter: React$ComponentType<{| + initialEntries?: Array, + initialIndex?: number, + getUserConfirmation?: GetUserConfirmation, + keyLength?: number, + children?: React$Node + |}> + + declare export var Router: React$ComponentType<{| + history: RouterHistory, + children?: React$Node + |}> + + declare export var Prompt: React$ComponentType<{| + message: string | ((location: Location) => string | boolean), + when?: boolean + |}> + + declare export var Redirect: React$ComponentType<{| + to: string | LocationShape, + push?: boolean, + from?: string, + exact?: boolean, + strict?: boolean + |}> + + declare export var Route: React$ComponentType<{| + caseSensitive?: boolean, + children?: React$Node, + element?: React$Element | null, + index?: boolean, + path?: string, + |}> + + declare export var Routes: React$ComponentType<{| + children?: React$Node, + location?: Location + |}> + + declare export function withRouter>( + WrappedComponent: Component + ): React$ComponentType<$Diff, ContextRouterVoid>>; + + declare type MatchPathOptions = { + path?: string | string[], + exact?: boolean, + sensitive?: boolean, + strict?: boolean + }; + + declare export function matchPath( + pathname: string, + options?: MatchPathOptions | string | string[], + parent?: Match + ): null | Match; + + declare export function generatePath(pattern?: string, params?: { +[string]: mixed }): string; +} diff --git a/definitions/npm/react-router-dom_v6.x.x/flow_v0.98.x-v0.103.x/test_react-router-dom.js b/definitions/npm/react-router-dom_v6.x.x/flow_v0.98.x-v0.103.x/test_react-router-dom.js new file mode 100644 index 0000000000..9c4a70f177 --- /dev/null +++ b/definitions/npm/react-router-dom_v6.x.x/flow_v0.98.x-v0.103.x/test_react-router-dom.js @@ -0,0 +1,380 @@ +// @flow +import React from "react"; +import { + BrowserRouter, + HashRouter, + Link, + NavLink, + matchPath, + withRouter, + Redirect, + Route +} from "react-router-dom"; +import type { + ContextRouter, + Match, + StaticRouterContext, + RouterHistory +} from "react-router-dom"; +import { it, describe } from "flow-typed-test"; + +describe("react-router-dom", () => { + describe("BrowserRouter", () => { + it("works", () => { + +
+ ; + + {}} + keyLength={3} + > +
+ ; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[incompatible-type] - basename must be a string + ; + }); + }); + + describe("HashRouter", () => { + it("works", () => { + +
+ ; + + {}} + hashType="noslash" + > +
+ ; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[incompatible-type] - hashType must be a string + ; + }); + }); + + describe("", () => { + it("works", () => { + About; + + + About + ; + + + About + ; + }); + + it("allows attributes of element", () => { + {}} + >About; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[prop-missing] - to prop is required + ; + + // $FlowExpectedError[incompatible-type] - to prop must be a string or LocationShape + ; + }); + }); + + describe("", () => { + it("works", () => { + About; + + true} + strict + exact + > + About + ; + + + About + ; + }); + + it("allows attributes of element", () => { + {}} + >About; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[prop-missing] - to prop is required + ; + + // $FlowExpectedError[incompatible-type] - to prop must be a string or LocationShape + ; + }); + }); + + describe("matchPath", () => { + it("works", () => { + const match: null | Match = matchPath("/the/pathname", { + path: "/the/:dynamicId", + exact: true, + strict: false + }); + const match2: null | Match = matchPath("/the/pathname", { + path: ["/the/:dynamicId", "/the/otherRoute"], + exact: true, + strict: false, + }); + const match3: null | Match = matchPath("/the/pathname", "/the/:dynamicId"); + const match4: null | Match = matchPath("/the/pathname", [ + "/the/:dynamicId", + "/the/otherRoute", + ]); + const match5: null | Match = matchPath("/the/pathname"); + }); + + it("raises an error if passed invalid argument", () => { + // $FlowExpectedError[incompatible-call] - pathname argument is required + matchPath(); + + // $FlowExpectedError[incompatible-type] - matchPath returns Match or null + const matchError: string = matchPath("/the/pathname", { + path: "the/:dynamicId" + }); + }); + }); + + describe("withRouter", () => { + type Props = { + history: RouterHistory, + location: Location, + match: Match, + staticContext: StaticRouterContext, + s: string + }; + describe("Stateless Functional Components", () => { + it("passes if the component is passed required props", () => { + const Comp = ({ + history, + location, + match, + staticContext, + s + }: Props) =>
; + const WrappedComp = withRouter(Comp); + ; + + const ChainedHOC = withRouter(WrappedComp); + ; + }); + + it("errors if the component is not passed correct props", () => { + const Comp = ({ + history, + location, + match, + staticContext, + s + }: Props) =>
; + const WrappedComp = withRouter(Comp); + // $FlowExpectedError[prop-missing] - missing prop "s" + ; + // $FlowExpectedError[incompatible-type] - wrong type + ; + + const ChainedHOC = withRouter(WrappedComp); + // $FlowExpectedError[prop-missing] - missing prop "s" + ; + // $FlowExpectedError[incompatible-type] - wrong type + ; + }); + + it("errors if trying to access a prop that withRouter does not supply", () => { + const Comp = ({ histry, s }: { histry: RouterHistory, s: string }) => ( +
+ ); + const WrappedComp = withRouter(Comp); + }); + + it("errors if using block() incorrectly", () => { + const Comp = ({history}: {history: RouterHistory}) => { + // $FlowExpectedError[incompatible-call] - wrong param + history.block(false); + + // These are valid + history.block('Are you sure you want to leave this page?'); + history.block((location, action) => { + return 'Are you sure you want to leave this page?'; + }); + + return
; + }; + const WrappedComp = withRouter(Comp); + }); + }); + + describe("Class Components", () => { + it("passes if the component is passed required props", () => { + class Comp extends React.Component { + render() { + return
; + } + } + const WrappedComp = withRouter(Comp); + ; + + const ChainedHOC = withRouter(WrappedComp); + ; + }); + + it("errors if the component is not passed the correct props", () => { + class Comp extends React.Component { + render() { + return
; + } + } + const WrappedComp = withRouter(Comp); + // $FlowExpectedError[prop-missing] - missing prop "s" + ; + // $FlowExpectedError[incompatible-type] - wrong type + ; + + const ChainedHOC = withRouter(WrappedComp); + // $FlowExpectedError[prop-missing] - missing prop "s" + ; + // $FlowExpectedError[incompatible-type] - wrong type + ; + }); + + it("passes if a required prop is handled by defaultProps", () => { + class Comp extends React.Component { + static defaultProps = { + s: "defaultS" + }; + render() { + return
; + } + } + const WrappedComp = withRouter(Comp); + ; + ; + + const ChainedHOC = withRouter(WrappedComp); + ; + ; + }); + + it("errors if a required prop that has a defaultProp is passed the wrong type", () => { + class Comp extends React.Component { + static defaultProps = { + s: "defaultS" + }; + render() { + return
; + } + } + const WrappedComp = withRouter(Comp); + // $FlowExpectedError[incompatible-type] - wrong type + ; + + const ChainedHOC = withRouter(WrappedComp); + // $FlowExpectedError[incompatible-type] - wrong type + ; + }); + }); + }); + + describe("Redirect", () => { + it("works", () => { + ; + + ; + + ; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[prop-missing] - to prop is required + ; + + // $FlowExpectedError[incompatible-type] - to prop must be a string or LocationShape + ; + + // $FlowExpectedError[prop-missing] - unexpected prop xxx + ; + }); + }); + + describe("Route", () => { + it("works", () => { + const Component = ({}) =>
Hi!
; + ; + + } />; + + ; + }); + + it("raises error if passed incorrect props", () => { + // $FlowExpectedError[incompatible-type] - prop must be a string + ; + + // $FlowExpectedError[prop-missing] - unexpected prop xxx + ; + }); + }) +});