TypeScript 3.0でredux-actionsのcreateActionみたいなものをつくる ref: https://qiita.com/terrierscript/items/b9687f610a96ab964ab2
export type AppActionCreators<
T extends { [key: string]: (...args) => any }
> = ReturnType<T[keyof T]>
export const counterActions = {
increment: createAppAction(ActionType.increment),
decrement: createAppAction(ActionType.decrement),
force: createAppAction(ActionType.force, (num: number) => {
return {
count: num
}
})
}
type CounterAction = AppActionCreators<typeof counterActions>
// もとの定義
// type CounterAction =
// | AppAction<ActionType.increment>
// | AppAction<ActionType.decrement>
// | AppAction<ActionType.force, { count: number }>
type CounterAction = ReturnType<
typeof increment | typeof decrement | typeof force
>
const increment = createAppAction(ActionType.increment)
const decrement = createAppAction(ActionType.decrement)
const force = createAppAction(ActionType.force, (num: number) => {
return {
count: num
}
})
// Extraの部分を作成する関数。Tuple in Rest parameter大活躍!
type ExtraFunction<Arg extends any[], R> = (...args: Arg) => R
type ActionCreator<Arg extends any[], Action> = (...args: Arg) => Action
// 関数のoverload
export function createAppAction<A extends string>(
type: A
): ActionCreator<any[], AppAction<A>>
export function createAppAction<A extends string, Arg extends any[], R>(
type: A,
fn: ExtraFunction<Arg, R>
): ActionCreator<Arg, AppAction<A, R>>
export function createAppAction(type, extraFunction?) {
return (...args) => {
if (extraFunction) {
const extra = extraFunction(...args)
return { type, ...extra }
}
return { type }
}
}