Help us understand the problem. What is going on with this article?

TypeScript 3.0でredux-actionsのcreateActionみたいなものをつくる

More than 1 year has passed since last update.

前回までのあらすじ

https://qiita.com/terrierscript/items/b3f9dd95a4c7afe0b102

上記の記事に書いてたけどちょっと別物になってきたので記事わけた。

もうちょっとなんとかしたかったこと

前回までのactionはボイラープレート多かったので、redux-actionsのcreateActionみたいなのがほしくなった。
本家のをそのまま使いたいところだが、payloadがpayload?で定義されており若干今回のactionの付帯情報まで決定させたいということが出来なかった。

あと、TypeScript 3.0で出ていたTuple in Rest parameterの使い所じゃん!って思ってテンションがあがったので使いたかった。
ということで下記は3.0以上向けになるので注意

コード

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

利用側はこんな感じになる

const increment = createAppAction(ActionType.increment)
const decrement = createAppAction(ActionType.decrement)
const force = createAppAction(ActionType.force, (num: number) => {
  return {
    count: num
  }
})

また、このcreateAppActionの定義とコメントいただいた ReturnTypeを駆使すると、更に楽ができる

// もとの定義
// type CounterAction =
//   | AppAction<ActionType.increment>
//   | AppAction<ActionType.decrement>
//   | AppAction<ActionType.force, { count: number }>

type CounterAction = ReturnType<
  typeof increment | typeof decrement | typeof force
>

気分が乗ってきたのでさらにactionをobjectでまとめてみるとこうなる

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>
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした