Skip to content

Instantly share code, notes, and snippets.

@JonasGao
Last active October 24, 2018 03:38
Show Gist options
  • Save JonasGao/3341e53456e2060fc1538aabf38ccef2 to your computer and use it in GitHub Desktop.
Save JonasGao/3341e53456e2060fc1538aabf38ccef2 to your computer and use it in GitHub Desktop.
make better type for dva
import { Action, AnyAction } from "redux"
type creator = (payload?: any, withNamespace?: boolean) => Action
type Creators<T> = {
[P in keyof T]: creator
};
interface Model<S, E, R> {
namespace: string,
state: S,
effects?: E,
reducers: R,
}
interface ModelWrap<S, E, R> {
model: Model<S, E, R>,
creators: {
effects: Creators<E>,
reducers: Creators<R>,
}
}
function _creators<T>(obj: T, namespace: string): Creators<T> {
return Object.keys(obj).reduce((obj, key) => {
obj[ key ] = function (payload = {} as any, withNamespace) {
payload.type = withNamespace ? `${namespace}/${key}` : key
return payload
}
return obj
}, {}) as Creators<T>
}
export interface DvaEffectCreators {
takeEvery: Function,
takeLatest: Function,
throttle: Function,
take: Function,
put: Function,
call: Function,
fork: Function,
spawn: Function,
join: Function,
cancel: Function,
select: Function,
actionChannel: Function,
flush: Function,
cancelled: Function,
race: Function,
all: Function,
}
export interface IDvaEffect<A = AnyAction> {
(action: A, effects: DvaEffectCreators): IterableIterator<any>
}
export interface IDvaWatchEffect {
(effects: DvaEffectCreators): void
}
export interface IDvaReducer<S, A = AnyAction> {
(state: S, action: A): void
}
export interface IDvaEffects {
[ extraProps: string ]: IDvaEffect | [ IDvaEffect | IDvaWatchEffect, any ];
}
export interface IDvaReducers<S> {
[ extraProps: string ]: IDvaReducer<S>;
}
export function createModel<S extends object,
E extends IDvaEffects,
R extends IDvaReducers<S>,
SS = {}>(
namespace: string,
state: S,
effects: E,
reducers: R,
subscriptions?: SS,
): ModelWrap<S, E, R> {
const model = {
namespace,
state,
effects,
reducers,
subscriptions
}
return {
model,
creators: {
effects: _creators(effects, namespace),
reducers: _creators(reducers, namespace),
}
}
}
const { model, creators: { effects, reducers } } = createModel(
"demo", // namespace
{
msg: null,
}, // state
{
* fetch(action, { put }) {
yield put(reducers.updateMsg({ msg: "Hello, World" }))
},
}, // effects
{
updateMsg(state, { msg }) {
// please use dva-immer plugin
state.msg = msg
}
} // reducers
)
export default model
// action creator for component or other model
export function fetch() {
return effects.fetch({}, true) // if true, creator will auto prefix namespace
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment