Skip to content

Commit

Permalink
feat(meta): add metadata support
Browse files Browse the repository at this point in the history
  • Loading branch information
omichelsen committed Aug 16, 2018
1 parent 375b379 commit 1ff5749
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 7 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,23 @@ Note that if you try and use the base function in a reducer, an error will be th
case String(fetchData): // throws an error
```

#### Metadata

You can add metadata to any action given a function that will receive the same arguments as the payload creator:

```js
import { createAsyncAction } from 'redux-promise-middleware-actions';

export const fetchData = createAsyncAction(
'FETCH_DATA',
(n: number) => fetch(...),
(n: number) => ({ n })
);


dispatch(fetchData(42)); // { type: 'FETCH_DATA_PENDING', meta: { n: 42 } }
```

### Async reducer

You can now handle the different events in your reducer by referencing the possible outcome states:
Expand Down
24 changes: 17 additions & 7 deletions src/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ export const onPending = (type: any) => `${type}_PENDING`;
export const onFulfilled = (type: any) => `${type}_FULFILLED`;
export const onRejected = (type: any) => `${type}_REJECTED`;

export interface IAction<Payload> {
export interface IAction<Payload, Metadata = undefined> {
type: string;
payload?: Payload;
error?: boolean;
meta?: Metadata;
}

export function createAction(
Expand All @@ -17,14 +18,22 @@ export function createAction<Payload, U extends any[]>(
payloadCreator: (...args: U) => Payload
): (...args: U) => IAction<Payload>;

export function createAction<Payload, U extends any[]>(
export function createAction<Payload, Metadata, U extends any[]>(
type: string,
payloadCreator: (...args: U) => Payload,
metadataCreator?: (...args: U) => Metadata
): (...args: U) => IAction<Payload, Metadata>;

export function createAction<Payload, Metadata, U extends any[]>(
type: string,
payloadCreator?: (...args: U) => Payload
): (...args: U) => IAction<Payload> {
payloadCreator?: (...args: U) => Payload,
metadataCreator?: (...args: U) => Metadata
): (...args: U) => IAction<Payload, Metadata> {
return Object.assign(
(...args: U) => ({
type,
...(payloadCreator && { payload: payloadCreator(...args) }),
...(metadataCreator && { meta: metadataCreator(...args) }),
}),
{ toString: () => type }
);
Expand All @@ -36,12 +45,13 @@ export interface IAsyncActionFunction<Payload> extends Function {
rejected: (payload?: any) => IAction<any>;
}

export function createAsyncAction<Payload, U extends any[]>(
export function createAsyncAction<Payload, Metadata, U extends any[]>(
type: string,
payloadCreator: (...args: U) => Promise<Payload>
payloadCreator: (...args: U) => Promise<Payload>,
metadataCreator?: (...args: U) => Metadata
) {
return Object.assign(
createAction(type, payloadCreator),
createAction(type, payloadCreator, metadataCreator),
{
toString: () => {
throw new Error(`Async action ${type} must be handled with pending, fulfilled or rejected`);
Expand Down
34 changes: 34 additions & 0 deletions test/actions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,40 @@ describe('actions', () => {
const action = createAction(TYPE, (a: number, b: number) => a + b);
assert.equal(action(40, 2).payload, 42);
});

describe('metadataCreator', () => {
it('should not have metadata', () => {
const action = createAction(TYPE, (n: number) => ({ n }));
assert.equal('meta' in action(42), false);
});

it('should forward same payload and metadata', () => {
const action = createAction(TYPE, (n: number) => ({ n }), (n: number) => ({ n }));
assert.deepEqual(action(42), {
type: TYPE,
payload: { n: 42 },
meta: { n: 42 },
});
});

it('should have different payload and metadata', () => {
const action = createAction(TYPE, (n: number) => ({ n }), () => ({ asdf: 1234 }));
assert.deepEqual(action(42), {
type: TYPE,
payload: { n: 42 },
meta: { asdf: 1234 },
});
});

it('should have only metadata', () => {
const action = createAction(TYPE, () => undefined, () => ({ asdf: 1234 }));
assert.deepEqual(action(), {
type: TYPE,
payload: undefined,
meta: { asdf: 1234 },
});
});
});
});

describe('createAsyncAction', () => {
Expand Down

0 comments on commit 1ff5749

Please sign in to comment.