From 6b8b4cb0b3461847d8b3dc5fa15e7d31ea1a575d Mon Sep 17 00:00:00 2001 From: Geir Sagberg Date: Wed, 28 Nov 2018 12:58:49 +0100 Subject: [PATCH] [redux-first-router] Update definitions for Options for 2.1 --- types/redux-first-router/index.d.ts | 101 ++++++++++++++++-- .../redux-first-router-tests.ts | 82 ++++++++------ 2 files changed, 140 insertions(+), 43 deletions(-) diff --git a/types/redux-first-router/index.d.ts b/types/redux-first-router/index.d.ts index 2184deed0b..1cf954b69f 100644 --- a/types/redux-first-router/index.d.ts +++ b/types/redux-first-router/index.d.ts @@ -6,6 +6,7 @@ // corydeppen // jscinoz // surgeboris +// geirsagberg // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.4 @@ -194,25 +195,107 @@ export interface NavigatorsConfig { }; } +export interface Bag { + action: ReceivedAction | Action; + extra: any; +} + export interface Options { - title?: string | SelectTitleState; + /** + * A prefix that will be prepended to the URL. For example, using a basename of '/playground', + * a route with the path '/home' would correspond to the URL path '/playground/home'. + */ + basename?: string; + /** + * Whether or not a trailing delimiter is allowed when matching path. + */ + strict?: boolean; + /** + * The name of the state key or a selector function to specify where in your Redux state tree + * Redux First Router should expect your page location reducer to be attached to. + */ location?: string | SelectLocationState; - notFoundPath?: string; - scrollTop?: boolean; - onBeforeChange?(dispatch: Dispatch, getState: StateGetter): void; - onAfterChange?(dispatch: Dispatch, getState: StateGetter): void; - onBackNext?(dispatch: Dispatch, getState: StateGetter): void; - restoreScroll?(history: History): ScrollBehavior; + /** + * The name of the state key or a selector function to specify where in your Redux state tree + * Redux First Router should expect your page title reducer to be attached to. + * This can be omitted if you attach the reducer at state.title. + */ + title?: string | SelectTitleState; + /** + * Can be set to false to bypass the initial dispatch, so you can do it manually, perhaps after running sagas. + */ initialDispatch?: boolean; - querySerializer?: QuerySerializer; - navigators?: NavigatorsConfig; + /** + * An array of entries to initialise history object. Useful for server side rendering and tests. + */ initialEntries?: HistoryEntries; + /** + * An object with parse and stringify methods, such as the `query-string` or `qs` libraries (or anything handmade). + * This will be used to handle querystrings. Without this option, query strings are ignored silently. + */ + querySerializer?: QuerySerializer; + /** + * The path where users may be redirected in 2 situations: when you dispatch an action with no matching path, + * or if you manually call dispatch(redirect({ type: NOT_FOUND })), where NOT_FOUND is an export from this package. + * The type in actions and state will be NOT_FOUND, which you can use to show a 404 page. + */ + notFoundPath?: string; + /** + * Whether or not window.scrollTo(0, 0) should be run on route changes so the user starts each page at the top. + */ + scrollTop?: boolean; + /** + * A function to update window/elements scroll position. + */ + restoreScroll?(history: History): ScrollBehavior; + /** + * A simple function that will be called before the routes change. + * It's passed your standard `dispatch` and `getState` arguments like a thunk, + * as well as the `bag` object as a third parameter, which contains the dispatched `action` and the configured `extra` value. + */ + onBeforeChange?(dispatch: Dispatch, getState: StateGetter, bag: Bag): void; + /** + * A simple function that will be called after the routes change. + * It's passed your standard `dispatch` and `getState` arguments like a thunk, + * as well as the `bag` object as a third parameter, which contains the dispatched `action` and the configured `extra` value. + */ + onAfterChange?(dispatch: Dispatch, getState: StateGetter, bag: Bag): void; + /** + * A simple function that will be called whenever the user uses the browser back/next buttons. + * It's passed your standard `dispatch` and `getState` arguments like a thunk, + * as well as the `bag` object as a third parameter, which contains the dispatched `action` + * and the configured `extra` value. Actions with kinds `back`, `next`, and `pop` trigger this. + */ + onBackNext?(dispatch: Dispatch, getState: StateGetter, bag: Bag): void; + /** + * A function receiving `message` and `callback` when navigation is blocked with `confirmLeave`. + * The message is the return value from `confirmLeave`. + * The callback can be called with `true` to unblock the navigation, or with `false` to cancel the navigation. + */ + displayConfirmLeave?: DisplayConfirmLeave; + /** + * A function returning a history object compatible with the popular `history` package. + */ createHistory?(): History; + /** + * A map of of your Redux state keys to _React Navigation_ navigators. + */ + navigators?: NavigatorsConfig; + /** + * An optional value that will be passed as part of the third `bag` argument to all options callbacks and routes thunk. + * It works much like the `withExtraArgument` feature of `redux-thunk` or the `context` argument of GraphQL resolvers. + * You can use it to pass any required context to your thunks without having to tightly couple them to it. + * For example, you could pass an instance of an API client initialised with authentication cookies, + * or a function `addReducer` to inject new code split reducers into the store. + */ + extra?: any; } export type Params = object; export type Payload = object; +export type DisplayConfirmLeave = (message: string, callback: (unblock: boolean) => void) => void; + export type ScrollUpdater = (performedByUser: boolean) => void; export const NOT_FOUND: '@@redux-first-router/NOT_FOUND'; diff --git a/types/redux-first-router/redux-first-router-tests.ts b/types/redux-first-router/redux-first-router-tests.ts index 5297be4175..0439f551c7 100644 --- a/types/redux-first-router/redux-first-router-tests.ts +++ b/types/redux-first-router/redux-first-router-tests.ts @@ -7,21 +7,24 @@ import { redirect, Action as ReduxFirstRouterAction, QuerySerializer, - pathToAction + pathToAction, + StateGetter, + Bag, + Navigators, + NavigationAction, + Nullable, + Route } from 'redux-first-router'; import { - AnyAction, createStore, applyMiddleware, Middleware, - MiddlewareAPI, - Store, Dispatch, compose, - Action, - StoreEnhancer, StoreEnhancerStoreCreator, - combineReducers + combineReducers, + AnyAction, + Store } from 'redux'; import { History } from 'history'; @@ -52,28 +55,40 @@ const routesMap: RoutesMap = { } }; -const { - reducer, - middleware, - enhancer, - initialDispatch, - thunk, -} = connectRoutes(routesMap, { - initialDispatch: false, - onBeforeChange: (dispatch, getState) => { - dispatch; // $ExpectType Dispatch - getState; // $ExpectType StateGetter +const { reducer, middleware, enhancer, initialDispatch, thunk } = connectRoutes(routesMap, { + basename: '/base', + strict: false, + location: state => { + const locationState = state.location; // $ExpectType LocationState + return locationState; + }, + title: state => { + const title = state.location.pathname; // $ExpectType string + return title; + }, + initialDispatch: false, + initialEntries: [], + querySerializer: { + stringify: queryString => { + queryString; // $ExpectType object + return ''; }, - location: state => { - const locationState = state.location; // $ExpectType LocationState - return locationState; - }, - title: state => { - const title = state.location.pathname; // $ExpectType string - return title; - }, - createHistory: () => history, - }); + parse: params => { + params; // $ExpectType string + return {}; + } + }, + notFoundPath: 'not-found', + scrollTop: true, + restoreScroll: (history: History) => { + return {}; + }, + onBeforeChange: (dispatch: Dispatch, getState: StateGetter, bag: Bag) => { }, + onAfterChange: (dispatch: Dispatch, getState: StateGetter, bag: Bag) => { }, + onBackNext: (dispatch: Dispatch, getState: StateGetter, bag: Bag) => { }, + displayConfirmLeave: (message: string, callback: (unblock: boolean) => void) => { }, + createHistory: (options?: any) => history +}); const dumbMiddleware: Middleware = store => next => action => next(action); @@ -89,10 +104,9 @@ const combined = combineReducers({ location: reducer }); const store = createStore(combined, storeEnhancer); // Test that `thunk()` has correct state types now that `store` is defined -thunk(store) - .then((t) => { - t = t!; // $ExpectType RouteThunk - }); +thunk(store).then(t => { + t = t!; // $ExpectType RouteThunk +}); const receivedAction: ReceivedAction = { type: 'HOME', @@ -102,8 +116,8 @@ actionToPath(receivedAction, routesMap); // $ExpectType string pathToAction('/', routesMap); // $ExpectType ReceivedAction const querySerializer: QuerySerializer = { - stringify: (params) => '', - parse: (queryString) => ({}) + stringify: params => '', + parse: queryString => ({}) }; actionToPath(receivedAction, routesMap, querySerializer); // $ExpectType string pathToAction('/', routesMap, querySerializer); // $ExpectType ReceivedAction