From 1f36fb3afd908ffa206570c4f0ecae4178f6944e Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Tue, 14 Jan 2020 17:28:30 +0000 Subject: [PATCH] `history`: switch default `LocationState` generic from `any` to `unknown` (#41580) * Enable `strictNullChecks` * Add test for generic state * Replace `any` with `PoorMansUnknown` * Define state generics --- types/history/history-tests.ts | 11 ++++++++++- types/history/index.d.ts | 5 ++++- types/history/tsconfig.json | 2 +- .../test/examples-from-react-router-website/Auth.tsx | 5 ++++- .../ModalGallery.tsx | 7 +++++-- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/types/history/history-tests.ts b/types/history/history-tests.ts index 89961ecf1e..91f7611755 100644 --- a/types/history/history-tests.ts +++ b/types/history/history-tests.ts @@ -9,6 +9,8 @@ let input = { value: "" }; { let history = createBrowserHistory<{ some: 'state' }>(); + history.location.state; // $ExpectType { some: "state"; } + // Listen for changes to the current location. The // listener is called once immediately. let unlisten = history.listen(function (location) { @@ -114,7 +116,8 @@ let input = { value: "" }; } { - let eventTarget: EventTarget; + const anything: any = {}; + const eventTarget: EventTarget = anything; DOMUtils.addEventListener(eventTarget, 'onload', function (event) { event.preventDefault(); }); DOMUtils.removeEventListener(eventTarget, 'onload', function (event) { event.preventDefault(); }); DOMUtils.getConfirmation('confirm?', (result) => console.log(result)); @@ -125,3 +128,9 @@ let input = { value: "" }; let supportsDOM = ExecutionEnvironment.canUseDOM; let isExtraneousPopstateEvent = DOMUtils.isExtraneousPopstateEvent; } + +{ + const anything: any = {}; + const history: History = anything; + history.location.state; // $ExpectType PoorMansUnknown +} diff --git a/types/history/index.d.ts b/types/history/index.d.ts index 44f3d6b826..0805d11e9b 100644 --- a/types/history/index.d.ts +++ b/types/history/index.d.ts @@ -49,7 +49,10 @@ export namespace History { location: Location, action: Action, ) => void; - export type LocationState = any; + // The value type here is a "poor man's `unknown`". When these types support TypeScript + // 3.0+, we can replace this with `unknown`. + type PoorMansUnknown = {} | null | undefined; + export type LocationState = PoorMansUnknown; export type Path = string; export type Pathname = string; export type Search = string; diff --git a/types/history/tsconfig.json b/types/history/tsconfig.json index 528d98e258..1b69f26078 100644 --- a/types/history/tsconfig.json +++ b/types/history/tsconfig.json @@ -7,7 +7,7 @@ ], "noImplicitAny": true, "noImplicitThis": true, - "strictNullChecks": false, + "strictNullChecks": true, "strictFunctionTypes": true, "baseUrl": "../", "typeRoots": [ diff --git a/types/react-router/test/examples-from-react-router-website/Auth.tsx b/types/react-router/test/examples-from-react-router-website/Auth.tsx index 816afa4c8f..dd974643d0 100644 --- a/types/react-router/test/examples-from-react-router-website/Auth.tsx +++ b/types/react-router/test/examples-from-react-router-website/Auth.tsx @@ -8,6 +8,7 @@ import { Redirect, withRouter } from 'react-router-dom'; +import { StaticContext } from 'react-router'; //////////////////////////////////////////////////////////// // 1. Click the public page @@ -68,7 +69,9 @@ const PrivateRoute: React.SFC = ({ component, ...rest }) => ( const Public: React.SFC = () =>

Public

; const Protected: React.SFC = () =>

Protected

; -class Login extends React.Component { +type Props = RouteComponentProps<{}, StaticContext, { from: { pathname: string; }; }>; + +class Login extends React.Component { state = { redirectToReferrer: false }; diff --git a/types/react-router/test/examples-from-react-router-website/ModalGallery.tsx b/types/react-router/test/examples-from-react-router-website/ModalGallery.tsx index c51d63ac0f..b890c7526b 100644 --- a/types/react-router/test/examples-from-react-router-website/ModalGallery.tsx +++ b/types/react-router/test/examples-from-react-router-website/ModalGallery.tsx @@ -6,6 +6,7 @@ import { Route, Link } from 'react-router-dom'; +import { StaticContext } from 'react-router'; // This example shows how to render two different screens // (or the same screen in a different context) at the same url, @@ -16,7 +17,9 @@ import { // are the same as before but now we see them inside a modal // on top of the old screen. -class ModalSwitch extends React.Component { +type Props = RouteComponentProps<{}, StaticContext, { modal: boolean }>; + +class ModalSwitch extends React.Component { // We can pass a location to that will tell it to // ignore the router's current location and use the location // prop instead. @@ -31,7 +34,7 @@ class ModalSwitch extends React.Component { // is still `/` even though its `/images/2`. previousLocation = this.props.location; - componentWillUpdate(nextProps: RouteComponentProps) { + componentWillUpdate(nextProps: Props) { const { location } = this.props; // set previousLocation if props.location is not modal if (