-
-
Notifications
You must be signed in to change notification settings - Fork 98
Description
Road to v2.0: New API
I'm working on New API using the new language feature (conditional types) coming to TypesScript in the next release (v2.8)
I have already published working version that is compatible with recent typescript@rc release
> to install yarn add typesafe-actions@next
Some changes are inspired by the suggestion from the past and I would really appreciate some feedback from their authors:
- Isnt createAction type parameter redundant when creatorFunction used? #18 @CzBuCHi
- suggestion: a default value for createAction with payload and meta #17 @Jack-Works
- Did you consider pushing this further towards more boilerplate-saving? #12 @flq
- Suggestion: ability to create "routines" #21 @duro
- Type assertion on the whole action #19 @farzadmf @dziamid
The implementation of a new API is taking place on the next branch, and will be released on the release of TypeScript v2.8.
all of the examples are working and have test's against them so they should be rock solid
Finished
ActionsUnion
conditional mapped type, will provide much cleaner and experience to get Union Type of actions
import { ActionsUnion } from 'typesafe-actions';
import * as actions from './todos-duck-module';
type RootAction = ActionsUnion<typeof actions>;
- ActionsUnion works nicely with nested actions from new
async
action creator (check below)
const actions = {
async: buildAction('GET_USER').async<number, { name: string }, string>(),
};
type RootAction = ActionsUnion<typeof actions>;
// { type: "GET_USER" & "REQUEST"; payload: number; } | { type: "GET_USER" & "SUCCESS"; payload: { name: string; }; } | { type: "GET_USER" & "FAILURE"; payload: string; }
- It also works recursively for deeply nested actions
const actions2 = {
very: { deep: { empty: buildAction('INCREMENT').empty() } },
payload: buildAction('ADD').payload<number>(),
};
type RootAction = ActionsUnion<typeof actions2>;
// { type: "INCREMENT"; } | { type: "ADD"; payload: number; }
ReturnType
getting type declaration of action will now be possible to derive from action creator on call site without the need to declare tons of boilerplate before-hand:
import { ReturnType, createAction } from 'typesafe-actions';
const increment = createAction('INCREMENT');
function incrementReducer(state: State, action: ReturnType<typeof increment>) {
...
buildAction
import { buildAction } from 'typesafe-actions'
function will accept action type and return an object with multiple methods to create different action creators described below:
buildAction('INCREMENT').empty()
const increment = buildAction('INCREMENT').empty();
expect(increment()).toEqual({ type: 'INCREMENT' }); // { type: 'INCREMENT' }
expect(getType(increment)).toBe('INCREMENT'); // 'INCREMENT'
buildAction('INCREMENT').payload<P>()
const add = buildAction('ADD').payload<number>();
expect(add(10)).toEqual({ type: 'ADD', payload: 10 }); // { type: 'ADD'; payload: number }
expect(getType(add)).toBe('ADD'); // 'ADD'
buildAction('INCREMENT').async<R, S, F>()
type User = { name: string };
const fetchUsers = buildAction('LIST_USERS').async<void, User[], string>();
expect(fetchUsers.request())
.toEqual({ type: 'LIST_USERS_REQUEST' }); // { type: 'LIST_USERS' & 'REQUEST' }
expect(fetchUsers.success([{ name: 'Piotr' }]))
.toEqual({ type: 'LIST_USERS_SUCCESS', payload: [{ name: 'Piotr' }] }); // { type: 'LIST_USERS' & 'SUCCESS'; payload: User[] }
expect(fetchUsers.failure('error message'))
.toEqual({ type: 'LIST_USERS_FAILURE', payload: 'error message' }); // { type: 'LIST_USERS' & 'FAILURE'; payload: string }
expect(getType(fetchUsers.request)).toBe('LIST_USERS_REQUEST'); // 'LIST_USERS' & 'REQUEST'
expect(getType(fetchUsers.success)).toBe('LIST_USERS_SUCCESS'); // 'LIST_USERS' & 'SUCCESS'
expect(getType(fetchUsers.failure)).toBe('LIST_USERS_FAILURE'); // 'LIST_USERS' & 'FAILURE'
buildAction('NOTIFY').fsa<P>(payloadCreator, metaCreator)
API compatible with
redux-actions
const notify = buildAction('NOTIFY').fsa<{ username: string; message?: string }>(
({ username, message }) => `${username}: ${message || ''}`,
({ username, message }) => ({ username, message })
); // { type: 'NOTIFY'; payload: string; meta: { username: string; message?: string }; }
...
Breaking changes
🎉NO BREAKING CHANGES 🎉
Known Issues
Migration to 1.2.0
Here is an migration example of example in the docs:
- simple payload action
// current v1.0
const add = createAction('ADD',
(amount: number) => ({ type: 'ADD', payload: amount }),
);
// migration to v1.2 (complete type-safety is still preserved)
const add = buildAction('ADD').payload<number>;
- advanced Flux Standard Action
// current v1.0
const notify = createAction('NOTIFY',
(username: string, message?: string) => ({
type: 'NOTIFY',
payload: `${username}: ${message || ''}`,
meta: { username, message },
}),
);
// migration to v1.2 (complete type-safety is still preserved)
const notify = buildAction('NOTIFY').fsa<{ username: string; message?: string }>(
({ username, message }) => `${username}: ${message || ''}`,
({ username, message }) => ({ username, message })
);