58
40

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

TypeScriptで Redux の Reducer部分を型安全かつスッキリ書く

Last updated at Posted at 2018-05-08

はじめに

TypeScript 2.8がリリースされ色々な機能が追加されました。
その中でもConditional types、特にReturnTypeがなかなか優秀で
今まで諦めていた部分がきれいに書けるようになっております。

そこで個人的にずさんになりがちな、ReduxのReducer周りを少し改良してみたのでご紹介

コード

const INCREMENT = 'app/example/INCREMENT' as const;
const SET_COUNT = 'app/example/SET_COUNT' as const;

export const increment = () => ({
  type: INCREMENT,
});

export const setCount = (num: number) => ({
  type: SET_COUNT,
  payload: {
    count: num,
  },
});

type Actions = (
  | ReturnType<typeof increment>
  | ReturnType<typeof setCount>
);

interface AppState {} // 本記事の趣旨に関係ないため割愛 
const initialState: AppState = {};

export default function reducer(
  state: AppState = initialState,
  action: Actions,
) {
  switch (action.type) {
    case INCREMENT:
      console.log(action.payload);
      // ↑ SET_COUNT以外でpayloadを参照するとエラーになる
      break;

    case SET_COUNT:
      console.log(action.payload);
      // ↑ OK
      break;

    default:
      const _: never = action;
      // ↑ ケースの定義もれがあった場合にエラーになる
  }
}

下で要点を解説していきます
また、今回は型をテーマにしていますので、
Reducerの処理自体は空っぽにしております

ReturnTypeの利用

TypeScript2.8の機能であるReturnTypeを利用することで、
ActionCreator関数の戻り値からActionの型を特定することができるようになりました。
こうすることでAction型定義の管理が少しだけ楽になります。

type Actions = (
  | ReturnType<typeof increment>
  | ReturnType<typeof setCount>
);

// ↓ こう解釈される

type Actions = {
    type: "app/example/INCREMENT";
} | {
    type: "app/example/SET_COUNT";
    payload: {
        count: number;
    };
}

TypeScript3.4で導入された const assertion を利用することで各定数がstringではなく、
その文字列の型として定義されるため↑のようにtypeが各アクションとして認識されます。

const INCREMENT = 'app/example/INCREMENT' as const;
const SET_COUNT = 'app/example/SET_COUNT' as const;

defaultの部分

default部分のnever型への代入についてはTypeScript 2.0のneverでTagged union typesの絞込を漏れ無くチェックする の記事で紹介されている素敵なテクニックです。

最後に

TypeScriptではanyを多用すればエラーを黙らせることはできますが
いかにして型安全に設計・実装できるかを考えるのが楽しいですよね。

実はもっといい方法があるのではないかと
うずうずしていますので、いい案があればぜひ教えていただきたいです。

参考記事

色々参考にさせていただきました。

58
40
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
58
40

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?