mirror of
https://github.com/gosticks/DefinitelyTyped.git
synced 2025-10-16 12:05:41 +00:00
[redux-pack]: add key signature to ActionMeta interface (#24785)
* [redux-pack]: add key signature to ActionMeta interface * [redux-pack]: improve type definitions for handler actions, allow passing custom metadata and all FSA compliant keys * [redux-pack]: fix no-unnecessary-generics error
This commit is contained in:
parent
326cb88142
commit
d8df907997
76
types/redux-pack/index.d.ts
vendored
76
types/redux-pack/index.d.ts
vendored
@ -1,52 +1,78 @@
|
||||
// Type definitions for redux-pack 0.1
|
||||
// Project: https://github.com/lelandrichardson/redux-pack
|
||||
// Definitions by: tansongyang <https://github.com/tansongyang>
|
||||
// dschuman <https://github.com/quicksnap>
|
||||
// pweinberg <https://github.com/no-stack-dub-sack>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
// TypeScript Version: 2.4
|
||||
|
||||
import {
|
||||
Action as ReduxAction,
|
||||
Middleware,
|
||||
Reducer,
|
||||
Reducer
|
||||
} from 'redux';
|
||||
|
||||
export const KEY: {
|
||||
readonly LIFECYCLE: 'redux-pack/LIFECYCLE'
|
||||
readonly TRANSACTION: 'redux-pack/TRANSACTION'
|
||||
readonly LIFECYCLE: 'redux-pack/LIFECYCLE';
|
||||
readonly TRANSACTION: 'redux-pack/TRANSACTION';
|
||||
};
|
||||
|
||||
export const LIFECYCLE: {
|
||||
readonly START: 'start'
|
||||
readonly SUCCESS: 'success'
|
||||
readonly FAILURE: 'failure'
|
||||
readonly START: 'start';
|
||||
readonly SUCCESS: 'success';
|
||||
readonly FAILURE: 'failure';
|
||||
};
|
||||
export type LIFECYCLEValues = 'start'| 'succes'| 'failure';
|
||||
|
||||
export type LIFECYCLEValues = 'start' | 'succes' | 'failure';
|
||||
|
||||
export const middleware: Middleware;
|
||||
|
||||
export interface Handlers<S> {
|
||||
start?: Reducer<S>;
|
||||
finish?: Reducer<S>;
|
||||
failure?: Reducer<S>;
|
||||
success?: Reducer<S>;
|
||||
always?: Reducer<S>;
|
||||
// MetaPayload differs from ActionMeta in that it is the object that the reducers
|
||||
// receive, instead of what is dispatched
|
||||
export type MetaPayload<M> = M & {
|
||||
['redux-pack/LIFECYCLE']?: LIFECYCLEValues;
|
||||
['redux-pack/TRANSACTION']?: string;
|
||||
};
|
||||
|
||||
// Incomplete typing
|
||||
export type PackActionPayload<Payload, M> = ReduxAction & {
|
||||
payload: Payload;
|
||||
meta: MetaPayload<M>;
|
||||
};
|
||||
|
||||
export type handlerReducer<S, A> = (state: S, action: A) => S;
|
||||
export interface Handlers<S, TSuccessPayload, TErrorPayload, TStartPayload, TMetaPayload> {
|
||||
start?: handlerReducer<S, PackActionPayload<TStartPayload, TMetaPayload>>;
|
||||
finish?: handlerReducer<S, ReduxAction>;
|
||||
failure?: handlerReducer<S, PackActionPayload<TErrorPayload, TMetaPayload>>;
|
||||
success?: handlerReducer<S, PackActionPayload<TSuccessPayload, TMetaPayload>>;
|
||||
always?: handlerReducer<S, ReduxAction>;
|
||||
}
|
||||
|
||||
export type GetState<S> = () => S;
|
||||
export interface ActionMeta<TState = {}, TSuccessPayload = {}, TErrorPayload = {}, TStartPayload = {}> {
|
||||
export interface ActionMeta<TFullState = {}, TSuccessPayload = {}, TErrorPayload = {}, TStartPayload = {}> {
|
||||
startPayload?: TStartPayload;
|
||||
onStart?(payload: TStartPayload, getState: GetState<TState>): void;
|
||||
onFinish?(resolved: boolean, getState: GetState<TState>): void;
|
||||
onSuccess?(response: TSuccessPayload, getState: GetState<TState>): void;
|
||||
onFailure?(error: TErrorPayload, getState: GetState<TState>): void;
|
||||
['redux-pack/LIFECYCLE']?: keyof LIFECYCLEValues;
|
||||
onStart?(payload: TStartPayload, getState: GetState<TFullState>): void;
|
||||
onFinish?(resolved: boolean, getState: GetState<TFullState>): void;
|
||||
onSuccess?(response: TSuccessPayload, getState: GetState<TFullState>): void;
|
||||
onFailure?(error: TErrorPayload, getState: GetState<TFullState>): void;
|
||||
['redux-pack/LIFECYCLE']?: LIFECYCLEValues;
|
||||
['redux-pack/TRANSACTION']?: string;
|
||||
}
|
||||
export interface Action<TState = {}, TSuccessPayload = {}, TErrorPayload = {}, TStartPayload = {}> extends ReduxAction {
|
||||
|
||||
export interface PackError { error: boolean; payload: any; }
|
||||
export interface Action<TFullState = {}, TSuccessPayload = {}, TErrorPayload = PackError, TStartPayload = {}, TMetaPayload = {}> extends ReduxAction {
|
||||
promise?: Promise<TSuccessPayload>;
|
||||
payload?: TSuccessPayload | TErrorPayload | TStartPayload;
|
||||
meta?: ActionMeta<TState, TSuccessPayload, TErrorPayload, TStartPayload>;
|
||||
meta?: ActionMeta<TFullState, TSuccessPayload, TErrorPayload, TStartPayload> & TMetaPayload;
|
||||
// add optional error key to conform to FSA design: https://github.com/redux-utilities/flux-standard-action
|
||||
// note that users of this middleware (using our types) must conform to FSA shaped actions or code will not compile
|
||||
error?: boolean | null;
|
||||
}
|
||||
export function handle<TState>(
|
||||
|
||||
export interface TFullState { [key: string]: any; }
|
||||
export function handle<TState, TSuccessPayload, TErrorPayload, TStartPayload, TMetaPayload>(
|
||||
state: TState,
|
||||
action: Action<TState, any, any, any>,
|
||||
handlers: Handlers<TState>)
|
||||
: TState;
|
||||
action: Action<TFullState, TSuccessPayload, TErrorPayload, TStartPayload, TMetaPayload>,
|
||||
handlers: Handlers<TState, TSuccessPayload, TErrorPayload, TStartPayload, TMetaPayload>,
|
||||
): TState;
|
||||
|
||||
@ -1,44 +1,87 @@
|
||||
import { handle, Action } from 'redux-pack';
|
||||
import { handle, Action, GetState } from 'redux-pack';
|
||||
|
||||
interface Foo {
|
||||
id: string;
|
||||
id: string;
|
||||
}
|
||||
interface FooState {
|
||||
foo: Foo | null;
|
||||
error: string | null;
|
||||
isLoading: boolean;
|
||||
currentUser: {
|
||||
id: string;
|
||||
};
|
||||
foo: Foo | null;
|
||||
bar: string;
|
||||
error: boolean;
|
||||
errorMsg: string;
|
||||
isLoading: boolean;
|
||||
metaPropOne: string;
|
||||
metaPropTwo: string;
|
||||
currentUser: {
|
||||
id: string;
|
||||
};
|
||||
}
|
||||
|
||||
// https://github.com/lelandrichardson/redux-pack/tree/v0.1.5#logging-beforeafter
|
||||
declare const Api: {
|
||||
getFoo(id: string): Promise<Foo>;
|
||||
getFoo(id: string): Promise<Foo>;
|
||||
};
|
||||
|
||||
declare function logSuccess(foo: Foo): void;
|
||||
function loadFoo(id: string): Action<FooState, Foo> {
|
||||
|
||||
interface MetaOne { propOne: string; }
|
||||
function loadFoo(id: string): Action<FooState, Foo, {}, {}, MetaOne> {
|
||||
return {
|
||||
type: LOAD_FOO,
|
||||
promise: Api.getFoo(id),
|
||||
meta: {
|
||||
onSuccess: logSuccess
|
||||
onSuccess: logSuccess,
|
||||
// pass custom metadata through to reducer
|
||||
// allowed by library, and a common redux pattern
|
||||
// https://github.com/lelandrichardson/redux-pack/blob/7818ffd4304d5f0e2c94056f3626a399fc9a5a10/src/middleware.js#L44
|
||||
propOne: 'some meta'
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
interface MetaTwo { propTwo: string; }
|
||||
function barError(): Action<FooState, Foo, {}, {}, MetaTwo> {
|
||||
return {
|
||||
type: BAR_ERROR,
|
||||
error: true,
|
||||
payload: new Error('this is an error action'),
|
||||
meta: {
|
||||
propTwo: 'other meta'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// bad (non-FSA action):
|
||||
function baz(baz: string): Action<FooState, Foo> {
|
||||
return {
|
||||
type: 'BAZ',
|
||||
// boo: baz // <-- will not compile, shape of action is not FSA
|
||||
// see line 62 & 63 of index.d.ts
|
||||
};
|
||||
}
|
||||
|
||||
// https://github.com/lelandrichardson/redux-pack/tree/v0.1.5#using-the-handle-helper
|
||||
const LOAD_FOO = 'LOAD_FOO';
|
||||
const BAR_ERROR = 'BAR_ERROR';
|
||||
declare const initialState: FooState;
|
||||
function fooReducer(state = initialState, action: Action<FooState, Foo, string | null>) {
|
||||
function fooReducer(state = initialState, action: Action<FooState, Foo, string | null, {}, MetaOne & MetaTwo>) {
|
||||
const { type, payload } = action;
|
||||
switch (type) {
|
||||
// example of non-redux-pack action
|
||||
// works as long as action is FSA compliant
|
||||
case BAR_ERROR:
|
||||
return {
|
||||
...state,
|
||||
error: action.error,
|
||||
errorMsg: action.payload,
|
||||
metaPropTwo: action.meta && action.meta.propTwo
|
||||
};
|
||||
case LOAD_FOO:
|
||||
return handle(state, action, {
|
||||
start: prevState => ({ ...prevState, isLoading: true, error: null, foo: null }),
|
||||
start: prevState => ({ ...prevState, isLoading: true, error: false, foo: null }),
|
||||
finish: prevState => ({ ...prevState, isLoading: false }),
|
||||
failure: prevState => ({ ...prevState, error: payload as string }),
|
||||
success: prevState => ({ ...prevState, foo: payload as Foo }),
|
||||
failure: prevState => ({ ...prevState, error: true, errorMsg: payload as string }),
|
||||
// must define both state and action params to correctly scope action (to access custom meta)
|
||||
success: (prevState, action) => ({ ...prevState, foo: payload as Foo, metaPropOne: action.meta.propOne }),
|
||||
always: prevState => prevState, // unnecessary, for the sake of example
|
||||
});
|
||||
default:
|
||||
@ -50,8 +93,8 @@ function fooReducer(state = initialState, action: Action<FooState, Foo, string |
|
||||
const DO_FOO = 'DO_FOO';
|
||||
declare function doFoo(): Promise<Foo>;
|
||||
declare function sendAnalytics(action: string, data: {
|
||||
userId: string,
|
||||
fooId: string,
|
||||
userId: string,
|
||||
fooId: string,
|
||||
}): void;
|
||||
function userDoesFoo(): Action<FooState, Foo> {
|
||||
return {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user