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

Create reducer #138

Merged
merged 22 commits into from
Apr 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
498 changes: 338 additions & 160 deletions README.md

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions codesandbox/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
6 changes: 6 additions & 0 deletions codesandbox/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"printWidth": 80,
"semi": true,
"singleQuote": true,
"trailingComma": "es5"
}
12,796 changes: 8,058 additions & 4,738 deletions codesandbox/package-lock.json

Large diffs are not rendered by default.

30 changes: 16 additions & 14 deletions codesandbox/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,31 @@
},
"dependencies": {
"@babel/polyfill": "7.4.3",
"@types/jest": "23.3.10",
"@types/react": "16.8.4",
"@types/react-dom": "16.8.2",
"@types/react-redux": "6.0.11",
"@types/react-router-dom": "4.3.1",
"@types/jest": "24.0.11",
"@types/react": "16.8.14",
"@types/react-dom": "16.8.4",
"@types/react-redux": "7.0.8",
"@types/react-router-dom": "4.3.2",
"@types/react-router-redux": "5.0.18",
"cuid": "2.1.6",
"jest": "23.6.0",
"react": "16.8.3",
"react-dom": "16.8.3",
"react-redux": "6.0.1",
"jest": "24.7.1",
"react": "16.8.6",
"react-dom": "16.8.6",
"react-redux": "7.0.2",
"react-redux-typescript-scripts": "1.5.0",
"react-router-dom": "4.3.1",
"react-router-redux": "5.0.0-alpha.9",
"react-scripts-ts": "3.1.0",
"redux": "4.0.1",
"redux-observable": "1.0.0",
"redux-observable": "1.1.0",
"reselect": "4.0.0",
"rxjs": "6.4.0",
"tslib": "1.9.3",
"tslint": "5.13.0",
"tslint-react": "3.6.0",
"typesafe-actions": "4.0.0",
"typescript": "3.4.3"
"tslint": "5.16.0",
"tslint-react": "4.0.0",
"typesafe-actions": "file:src/typesafe-actions",
"typescript": "3.4.4",
"utility-types": "3.5.0"
},
"devDependencies": {}
}
1 change: 0 additions & 1 deletion codesandbox/src/env.ts

This file was deleted.

6 changes: 3 additions & 3 deletions codesandbox/src/features/todos/components/TodoList.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { RootState } from 'MyTypes';
import { RootState } from 'typesafe-actions';
import * as React from 'react';
import { connect } from 'react-redux';

import * as selectors from '../selectors';
import { removeTodo } from '../actions';
import * as actions from '../actions';

import TodoListItem from './TodoListItem';

Expand All @@ -12,7 +12,7 @@ const mapStateToProps = (state: RootState) => ({
todos: selectors.getTodos(state.todos),
});
const dispatchProps = {
removeTodo,
removeTodo: actions.removeTodo,
};

type Props = ReturnType<typeof mapStateToProps> & typeof dispatchProps;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { RootState } from 'typesafe-actions';
import * as React from 'react';
import { connect } from 'react-redux';

import { loadTodosAsync, saveTodosAsync } from '../actions';
import { RootState } from 'MyTypes';

const mapStateToProps = (state: RootState) => ({
isLoading: state.todos.isLoadingTodos,
Expand Down
3 changes: 1 addition & 2 deletions codesandbox/src/features/todos/epics.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { RootAction, RootState, Services } from 'MyTypes';
import { Epic } from 'redux-observable';
import { from, of } from 'rxjs';
import { filter, switchMap, map, catchError } from 'rxjs/operators';
import { isActionOf } from 'typesafe-actions';
import { RootAction, RootState, Services, isActionOf } from 'typesafe-actions';

import { loadTodosAsync, saveTodosAsync } from './actions';
import { getTodos } from './selectors';
Expand Down
68 changes: 25 additions & 43 deletions codesandbox/src/features/todos/reducer.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,32 @@
import { RootAction } from 'MyTypes';
import { Todo } from 'MyModels';
import { combineReducers } from 'redux';
import { getType } from 'typesafe-actions';
import { createReducer } from 'typesafe-actions';

import * as actions from './actions';
import { loadTodosAsync, addTodo, removeTodo } from './actions';

export type SandboxState = Readonly<{
isLoadingTodos: boolean;
todos: Todo[];
}>;
export const isLoadingTodos = createReducer(false as boolean)
.handleAction([loadTodosAsync.request], (state, action) => true)
.handleAction(
[loadTodosAsync.success, loadTodosAsync.failure],
(state, action) => false
);

export default combineReducers<SandboxState, RootAction>({
isLoadingTodos: (state = false, action) => {
switch (action.type) {
case getType(actions.loadTodosAsync.request):
return true;

case getType(actions.loadTodosAsync.success):
case getType(actions.loadTodosAsync.failure):
return false;

default:
return state;
}
},
todos: (
state = [
{
id: '0',
title: 'You can add new todos using the form or load saved snapshot...',
},
],
action
) => {
switch (action.type) {
case getType(actions.addTodo):
return [...state, action.payload];

case getType(actions.removeTodo):
return state.filter(i => i.id !== action.payload);

case getType(actions.loadTodosAsync.success):
return action.payload;

default:
return state;
}
export const todos = createReducer([
{
id: '0',
title: 'You can add new todos using the form or load saved snapshot...',
},
] as Todo[])
.handleAction(loadTodosAsync.success, (state, action) => action.payload)
.handleAction(addTodo, (state, action) => [...state, action.payload])
.handleAction(removeTodo, (state, action) =>
state.filter(i => i.id !== action.payload)
);

const todosReducer = combineReducers({
isLoadingTodos,
todos,
});

export default todosReducer;
export type TodosState = ReturnType<typeof todosReducer>;
4 changes: 2 additions & 2 deletions codesandbox/src/features/todos/selectors.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// import { createSelector } from 'reselect';

import { SandboxState } from './reducer';
import { TodosState } from './reducer';

export const getTodos = (state: SandboxState) => state.todos;
export const getTodos = (state: TodosState) => state.todos;
8 changes: 0 additions & 8 deletions codesandbox/src/index.js

This file was deleted.

8 changes: 2 additions & 6 deletions codesandbox/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
// tslint:disable-next-line:no-import-side-effect
// tslint:disable-next-line: no-import-side-effect
import '@babel/polyfill';
// console.log('polyfills');

// tslint:disable-next-line:no-import-side-effect
// tslint:disable-next-line: no-import-side-effect
import 'tslib';
// tslint:disable-next-line:no-import-side-effect
import './env';

import * as React from 'react';
import { render } from 'react-dom';
Expand Down
4 changes: 3 additions & 1 deletion codesandbox/src/services/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
declare module 'MyTypes' {
import {} from 'typesafe-actions';

declare module 'typesafe-actions' {
export type Services = typeof import('./index').default;
}
2 changes: 1 addition & 1 deletion codesandbox/src/store/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { RootAction, RootState, Services } from 'MyTypes';
import { createStore, applyMiddleware } from 'redux';
import { createEpicMiddleware } from 'redux-observable';
import { RootAction, RootState, Services } from 'typesafe-actions';

import { composeEnhancers } from './utils';
import rootReducer from './root-reducer';
Expand Down
2 changes: 1 addition & 1 deletion codesandbox/src/store/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { StateType, ActionType } from 'typesafe-actions';

declare module 'MyTypes' {
declare module 'typesafe-actions' {
export type Store = StateType<typeof import('./index').default>;
export type RootAction = ActionType<typeof import('./root-action').default>;
export type RootState = StateType<typeof import('./root-reducer').default>;
Expand Down
37 changes: 37 additions & 0 deletions codesandbox/src/typesafe-actions/action.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { TypeConstant } from './type-helpers';
export declare function action<T extends TypeConstant, E>(type: T, payload: undefined, meta: undefined, error: E): {
type: T;
error: E;
};
export declare function action<T extends TypeConstant, M, E>(type: T, payload: undefined, meta: M, error: E): {
type: T;
meta: M;
error: E;
};
export declare function action<T extends TypeConstant, P, E>(type: T, payload: P, meta: undefined, error: E): {
type: T;
payload: P;
error: E;
};
export declare function action<T extends TypeConstant, P, M, E>(type: T, payload: P, meta: M, error: E): {
type: T;
payload: P;
meta: M;
error: E;
};
export declare function action<T extends TypeConstant, M>(type: T, payload: undefined, meta: M): {
type: T;
meta: M;
};
export declare function action<T extends TypeConstant, P, M>(type: T, payload: P, meta: M): {
type: T;
payload: P;
meta: M;
};
export declare function action<T extends TypeConstant, P>(type: T, payload: P): {
type: T;
payload: P;
};
export declare function action<T extends TypeConstant>(type: T): {
type: T;
};
12 changes: 12 additions & 0 deletions codesandbox/src/typesafe-actions/create-action-deprecated.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { TypeConstant } from './type-helpers';
interface FSA<T extends TypeConstant, P = {}, M = {}, E = boolean> {
type: T;
payload?: P;
meta?: M;
error?: E;
}
export declare function createActionDeprecated<T extends TypeConstant, AC extends (...args: any[]) => FSA<T>>(actionType: T, creatorFunction: AC): AC;
export declare function createActionDeprecated<T extends TypeConstant, AC extends () => {
type: T;
}>(actionType: T): AC;
export {};
17 changes: 17 additions & 0 deletions codesandbox/src/typesafe-actions/create-action.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { TypeConstant, ActionCreator } from './type-helpers';
export declare type PayloadMetaAction<T extends TypeConstant, P, M> = P extends undefined ? M extends undefined ? {
type: T;
} : {
type: T;
meta: M;
} : M extends undefined ? {
type: T;
payload: P;
} : {
type: T;
payload: P;
meta: M;
};
export declare function createAction<T extends TypeConstant, AC extends ActionCreator<T> = () => {
type: T;
}>(type: T, createHandler?: (actionCallback: <P = undefined, M = undefined>(payload?: P, meta?: M) => PayloadMetaAction<T, P, M>) => AC): AC;
10 changes: 10 additions & 0 deletions codesandbox/src/typesafe-actions/create-async-action.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { TypeConstant, ActionBuilderConstructor } from './type-helpers';
export interface AsyncActionBuilder<T1 extends TypeConstant, T2 extends TypeConstant, T3 extends TypeConstant> {
<P1, P2, P3>(): AsyncActionBuilderConstructor<T1, T2, T3, P1, P2, P3>;
}
export declare type AsyncActionBuilderConstructor<T1 extends TypeConstant, T2 extends TypeConstant, T3 extends TypeConstant, P1, P2, P3> = {
request: ActionBuilderConstructor<T1, P1>;
success: ActionBuilderConstructor<T2, P2>;
failure: ActionBuilderConstructor<T3, P3>;
};
export declare function createAsyncAction<T1 extends TypeConstant, T2 extends TypeConstant, T3 extends TypeConstant>(requestType: T1, successType: T2, failureType: T3): AsyncActionBuilder<T1, T2, T3>;
4 changes: 4 additions & 0 deletions codesandbox/src/typesafe-actions/create-custom-action.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { ActionCreator, TypeConstant } from './type-helpers';
export declare function createCustomAction<T extends TypeConstant, AC extends ActionCreator<T> = () => {
type: T;
}>(type: T, createHandler?: (type: T) => AC): AC;
17 changes: 17 additions & 0 deletions codesandbox/src/typesafe-actions/create-reducer.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { RootAction } from './';
import { Reducer, Action } from './type-helpers';
declare type HandleActionChainApi<TState, TNotHandledAction extends Action, TRootAction extends Action> = <TType extends TNotHandledAction['type'], TTypeAction extends TNotHandledAction extends {
type: TType;
} ? TNotHandledAction : never, TCreator extends (...args: any[]) => TNotHandledAction, TCreatorAction extends TNotHandledAction extends ReturnType<TCreator> ? TNotHandledAction : never, TActionIntersection extends TTypeAction extends TCreatorAction ? TTypeAction : never>(singleOrMultipleCreatorsAndTypes: TType | TType[] | TCreator | TCreator[], reducer: (state: TState, action: TActionIntersection) => TState) => [Exclude<TNotHandledAction, TTypeAction & TCreatorAction>] extends [never] ? Reducer<TState, TRootAction> & {
handlers: Record<TActionIntersection['type'], (state: TState, action: TRootAction) => TState>;
} : Reducer<TState, TRootAction> & {
handlers: Record<TActionIntersection['type'], (state: TState, action: TRootAction) => TState>;
handleAction: HandleActionChainApi<TState, Exclude<TNotHandledAction, TTypeAction & TCreatorAction>, TNotHandledAction>;
};
export declare function createReducer<TState, TRootAction extends Action = RootAction>(initialState: TState, initialHandlers?: Record<RootAction['type'], (state: TState, action: RootAction) => TState>): Reducer<TState, TRootAction> & {
handlers: {
readonly [x: string]: (state: TState, action: any) => TState;
};
readonly handleAction: HandleActionChainApi<TState, TRootAction, TRootAction>;
};
export {};
6 changes: 6 additions & 0 deletions codesandbox/src/typesafe-actions/create-standard-action.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { TypeConstant, ActionBuilderConstructor, ActionBuilderMap } from './type-helpers';
export interface ActionBuilder<T extends TypeConstant> {
<P = undefined, M = undefined>(): ActionBuilderConstructor<T, P, M>;
map<R, P = undefined, M = undefined>(fn: (payload: P, meta: M) => R): ActionBuilderMap<T, R, P, M>;
}
export declare function createStandardAction<T extends TypeConstant>(type: T): ActionBuilder<T>;
2 changes: 2 additions & 0 deletions codesandbox/src/typesafe-actions/get-type.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { TypeConstant, ActionCreator, TypeMeta } from './type-helpers';
export declare function getType<T extends TypeConstant>(actionCreator: ActionCreator<T> & TypeMeta<T>): T;
11 changes: 11 additions & 0 deletions codesandbox/src/typesafe-actions/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export { action } from './action';
export { createAction } from './create-action';
export { createStandardAction } from './create-standard-action';
export { createCustomAction } from './create-custom-action';
export { createAsyncAction } from './create-async-action';
export { createReducer } from './create-reducer';
export { getType } from './get-type';
export { isOfType } from './is-of-type';
export { isActionOf } from './is-action-of';
export { TypeConstant, Action, ActionCreator, Reducer, EmptyAction, PayloadAction, MetaAction, PayloadMetaAction, EmptyAC, PayloadAC, PayloadMetaAC, TypeMeta, ActionType, StateType, } from './type-helpers';
export { createActionDeprecated } from './create-action-deprecated';
Loading