Skip to content
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

[reduxjs/toolkit] Fix definition errors #4481

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/src/commands/runTests.js
Expand Up @@ -400,7 +400,7 @@ export async function writeFlowConfig(
'server.max_workers=0',
semver.gte(version, '0.200.0') ? 'exact_by_default=true' : '', // from version 0.202.0 default is true
// Fixes out of shared memory error for Mac Rosetta 2, see https://github.com/facebook/flow/issues/8538
'sharedmemory.heap_size=3221225472',
semver.gte(version, '0.78.0') ? 'sharedmemory.heap_size=3221225472' : '',
semver.lt(version, '0.125.0')
? 'suppress_comment=\\\\(.\\\\|\\n\\\\)*\\\\$FlowExpectedError'
: '',
Expand Down
Expand Up @@ -6,8 +6,8 @@ import {
configureStore,
type Middleware,
type Store,
type Action,
} from '@reduxjs/toolkit';
import { type Action } from 'redux';

describe('@redux/toolkit', () => {
describe('createAction', () => {
Expand Down
Expand Up @@ -449,7 +449,7 @@ declare module '@reduxjs/toolkit' {
* function (either directly or indirectly by passing an object as `reducer`),
* this must be an object with the same shape as the reducer map keys.
*/
preloadedState?: { [key: string]: any },
preloadedState?: { [key: string]: any, ... },
/**
* The store enhancers to apply. See Redux's `createStore()`.
* All enhancers will be included before the DevTools Extension enhancer.
Expand Down
Expand Up @@ -449,7 +449,7 @@ declare module '@reduxjs/toolkit' {
* function (either directly or indirectly by passing an object as `reducer`),
* this must be an object with the same shape as the reducer map keys.
*/
preloadedState?: { [key: string]: any },
preloadedState?: { [key: string]: any, ... },
/**
* The store enhancers to apply. See Redux's `createStore()`.
* All enhancers will be included before the DevTools Extension enhancer.
Expand Down
Expand Up @@ -6,6 +6,7 @@ import {
configureStore,
type Middleware,
type Store,
type GetDefaultMiddleware,
} from '@reduxjs/toolkit';
import type { Action } from 'redux';

Expand Down Expand Up @@ -55,12 +56,19 @@ describe('@redux/toolkit', () => {
});

describe('createStore', () => {
const reducer = createReducer({}, {
const reducer = createReducer({ name: 'test' }, {
'a': (state, action) => {
state.name = action.payload.name;
},
});


createReducer({
name: 'a',
}, {
'a': (state) => { state.name; return state },
})

test('with basic reducer', () => {
configureStore({
reducer,
Expand All @@ -72,19 +80,23 @@ describe('@redux/toolkit', () => {
...
}, Action<{ ... }>> = configureStore({
reducer: {
test: (a) => ({}),
test2: (a) => 2,
test: (a: any) => ({}),
test2: (a: any) => 2,
},
});

store.getState().test2.toFixed(2);
// $FlowExpectedError[prop-missing]
store.getState().foo;

const failedStore: Store<{|
test: { ... },
test2: number,
// $FlowExpectedError[prop-missing] foo is missing
|}, Action<{ ... }>> = configureStore({
reducer: {
test: (a) => ({}),
test2: (a) => 2,
test: (a: any) => ({}),
test2: (a: any) => 2,
foo: () => 'bar',
},
});
Expand Down Expand Up @@ -131,7 +143,7 @@ describe('@redux/toolkit', () => {

configureStore({
reducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger),
middleware: (getDefaultMiddleware: GetDefaultMiddleware) => getDefaultMiddleware().concat(logger),
})

configureStore({
Expand Down
Expand Up @@ -231,7 +231,7 @@ declare module '@reduxjs/toolkit' {
* @param actionCreator
* @param reducer
*/
addCase<ActionCreator = TypedActionCreator<string>>(actionCreator: ActionCreator, reducer: (State, ReturnType<ActionCreator>) => void): ActionReducerMapBuilder<State>;
addCase<ActionCreator = TypedActionCreator<string>>(actionCreator: ActionCreator, reducer: (state: State, action: Action<string>) => void): ActionReducerMapBuilder<State>;
/**
* Add a case reducer for actions with the specified type.
* @param type
Expand Down Expand Up @@ -383,11 +383,10 @@ declare module '@reduxjs/toolkit' {
*
* @public
*/
declare function createReducer<S, CR = {| [string]: (S, Action<string>) => S |}, A = any>(
declare function createReducer<S>(
initialState: S,
actionsMap: CR
): (state: S | void, action: A) => S;

actionsMap: { [key: string]: ((state: S, action: Action<string>) => S | void)}
): (state: S | void, action: Action<string>) => S;

/**
* A utility function that allows defining a reducer as a mapping from action
Expand All @@ -406,10 +405,10 @@ declare module '@reduxjs/toolkit' {
*
* @public
*/
declare function createReducer<S, A>(
declare function createReducer<S>(
initialState: S,
builderCallback: (builder: ActionReducerMapBuilder<S>) => void,
): (state: S | void, action: A) => S;
): (state: S | void, action: Action<string>) => S;

/**
* Callback function type, to be used in `ConfigureStoreOptions.enhancers`
Expand All @@ -418,10 +417,12 @@ declare module '@reduxjs/toolkit' {

declare type ReducersMapObject = <V>(V) => Reducer<V, Action<any>>;

declare type GetDefaultMiddleware = () => Middlewares<any>;

/**
* Options for `configureStore()`.
*/
declare type ConfigureStoreOptions<S, A, M> = {|
declare type ConfigureStoreOptions<S, A, M = Middlewares<S>> = {|
/**
* A single reducer function that will be used as the root reducer, or an
* object of slice reducers that will be passed to `combineReducers()`.
Expand All @@ -434,7 +435,7 @@ declare module '@reduxjs/toolkit' {
* @example `middleware: (gDM) => gDM().concat(logger, apiMiddleware, yourCustomMiddleware)`
* @see https://redux-toolkit.js.org/api/getDefaultMiddleware#intended-usage
*/
middleware?: M | ((gDM: () => M) => M),
middleware?: M | ((gDM: GetDefaultMiddleware) => M),
/**
* Whether to enable Redux DevTools integration. Defaults to `true`.
*
Expand All @@ -449,7 +450,7 @@ declare module '@reduxjs/toolkit' {
* function (either directly or indirectly by passing an object as `reducer`),
* this must be an object with the same shape as the reducer map keys.
*/
preloadedState?: { [key: string]: any },
preloadedState?: { [key: string]: any, ... },
/**
* The store enhancers to apply. See Redux's `createStore()`.
* All enhancers will be included before the DevTools Extension enhancer.
Expand All @@ -469,5 +470,5 @@ declare module '@reduxjs/toolkit' {
*
* @public
*/
declare function configureStore<S = any, A: Action<any> = Action<any>, M: Middlewares<S> = []>(options: ConfigureStoreOptions<S, A, M>): Store<S, A>;
declare function configureStore<S = any, A: Action<any> = Action<any>>(options: ConfigureStoreOptions<S, A>): Store<S, A>;
}
@@ -0,0 +1,5 @@
{
"deps": {
"redux": ["v4.x.x"]
}
}
@@ -0,0 +1,160 @@
// @flow
import { describe, it, test } from 'flow-typed-test';
import {
createAction,
createReducer,
configureStore,
type Middleware,
type Store,
type GetDefaultMiddleware,
} from '@reduxjs/toolkit';
import type { Action } from 'redux';

describe('@redux/toolkit', () => {
describe('createAction', () => {
it('supports being called with an action type string', () => {
createAction('increment');
});

it('supports being called with an action type string and a payload type', () => {
type Payload = $ReadOnly<{|
someData: 'The FitnessGram Pacer Test is a multistage aerobic capacity test that progressively gets...',
|}>;

createAction<Payload>('injectData');
});
});

describe('createReducer', () => {
it('supports being called with an object map', () => {
const state = {
name: 'Pelle',
};

const SET_NAME = 'SET_NAME';

createReducer(state, {
[SET_NAME]: (state, action) => {
state.name = action.payload.name;
}
});
});

it('supports being called with an builder callback', () => {
const state = {
name: 'Pelle',
};

const setName = createAction<string>('SET_NAME');

createReducer(state, builder => {
builder.addCase(setName, (state, action) => {
state.name = action.payload.name;
});
});
});
});

describe('createStore', () => {
const reducer = createReducer({ name: 'test' }, {
'a': (state, action) => {
state.name = action.payload.name;
},
});


createReducer({
name: 'a',
}, {
'a': (state) => { state.name; return state },
})

test('with basic reducer', () => {
configureStore({
reducer,
});

const store: Store<{
test: { ... },
test2: number,
...
}, Action<{ ... }>> = configureStore({
reducer: {
test: (a: any) => ({}),
test2: (a: any) => 2,
},
});

store.getState().test2.toFixed(2);
// $FlowExpectedError[prop-missing]
store.getState().foo;

const failedStore: Store<{|
test: { ... },
test2: number,
|}, Action<{ ... }>> = configureStore({
// $FlowExpectedError[incompatible-call] foo is missing
reducer: {
test: (a: any) => ({}),
test2: (a: any) => 2,
foo: () => 'bar',
},
});

// const failedStore2: Store<{
// test: { ... },
// // Expect this to fail but currently does not
// test2: string,
// ...
// }, Action<{ ... }>> = configureStore({
// reducer: {
// test: (a) => ({}),
// test2: (a) => 2,
// },
// });
});

test('full example', () => {
const preloadedState = {
todos: [
{
text: 'Eat food',
completed: true,
},
{
text: 'Exercise',
completed: false,
},
],
visibilityFilter: 'SHOW_COMPLETED',
};
const reduxBatch: any = {};

configureStore({
reducer,
devTools: process.env.NODE_ENV !== 'production',
preloadedState,
enhancers: [reduxBatch],
})
});

test('middleware', () => {
declare var logger: Middleware<any, any>;

configureStore({
reducer,
middleware: (getDefaultMiddleware: GetDefaultMiddleware) => getDefaultMiddleware().concat(logger),
})

configureStore({
reducer,
middleware: [logger],
})
});

test('errors', () => {
// $FlowExpectedError[incompatible-call]
configureStore();
})
});
});