terrierscript
8/3/2018 - 1:16 AM

TypeScript 3.0でredux-actionsのcreateActionみたいなものをつくる ref: https://qiita.com/terrierscript/items/b9687f610a96ab964ab2

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 }
  }
}