メインコンテンツへスキップ
非公式ベータ版翻訳

このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →

Redux Toolkit TypeScriptクイックスタート

学べる内容
  • TypeScriptでRedux ToolkitとReact-Reduxをセットアップして使用する方法
前提知識

はじめに

Redux Toolkit TypeScriptクイックスタートチュートリアルへようこそ! このチュートリアルでは、TypeScriptをRedux ToolkitおよびReact-Reduxとともに使用する方法を簡潔に説明します

このページではTypeScript関連の設定方法に焦点を当てています。Reduxの概要や動作原理、Redux Toolkitの完全な使用例については、「チュートリアルインデックス」ページのリンク先チュートリアルを参照してください。

Redux ToolkitはTypeScriptで書かれているため、TS型定義が組み込まれています。

React Reduxもバージョン8以降はTypeScriptで書かれており、独自の型定義を含んでいます。

Create-React-App向けRedux+TSテンプレートには、これらのパターンが設定済みの動作サンプルが含まれています。

プロジェクト設定

Root StateとDispatch型の定義

Redux ToolkitのconfigureStore APIには追加の型定義は不要です。ただし、RootState型とDispatch型を抽出して必要に応じて参照できるようにすることをお勧めします。ストア自体からこれらの型を推論することで、ステートスライスを追加したりミドルウェア設定を変更したりした際に正しく更新されます。

これらは型であるため、app/store.tsなどのストア設定ファイルから直接エクスポートし、他のファイルに直接インポートしても安全です。

app/store.ts
import { configureStore } from '@reduxjs/toolkit'
// ...

export const store = configureStore({
reducer: {
posts: postsReducer,
comments: commentsReducer,
users: usersReducer
}
})

// Infer the `RootState`, `AppDispatch`, and `AppStore` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
export type AppStore = typeof store

型付きフックの定義

各コンポーネントにRootStateAppDispatch型をインポートすることも可能ですが、アプリケーションで使用するために型付きバージョンのuseDispatchおよびuseSelectorフックを作成する方が良いです。これには重要な理由がいくつかあります:

  • useSelectorの場合、毎回(state: RootState)と型指定する手間が省けます

  • useDispatchの場合、デフォルトのDispatch型はサンクを認識しません。サンクを正しくディスパッチするには、サンクミドルウェアの型を含むストアのカスタマイズ済みAppDispatch型を使用し、それをuseDispatchとともに使う必要があります。事前に型付けされたuseDispatchフックを追加すれば、必要な場所でAppDispatchをインポートし忘れるのを防げます。

これらは型ではなく実際の変数であるため、ストア設定ファイルではなくapp/hooks.tsのような別ファイルで定義することが重要です。これにより、フックを使用する必要がある任意のコンポーネントファイルにインポートでき、循環インポートの依存関係問題を回避できます。

app/hooks.ts
import { useDispatch, useSelector } from 'react-redux'
import type { AppDispatch, RootState } from './store'

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()

アプリケーションでの使用

スライスのステートとアクション型の定義

各スライスファイルでは初期ステート値の型を定義すべきです。これによりcreateSliceが各ケースリデューサーのstate型を正しく推論できます。

生成されるすべてのアクションは、Redux ToolkitのPayloadAction<T>型を使用して定義する必要があります。この型はジェネリック引数としてaction.payloadフィールドの型を取ります。

ここではストアファイルからRootState型を安全にインポートできます。循環インポートになりますが、TypeScriptコンパイラは型に関してこれを正しく処理できます。セレクター関数の作成などのユースケースで必要になる場合があります。

features/counter/counterSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import type { RootState } from '../../app/store'

// Define a type for the slice state
export interface CounterState {
value: number
}

// Define the initial state using that type
const initialState: CounterState = {
value: 0
}

export const counterSlice = createSlice({
name: 'counter',
// `createSlice` will infer the state type from the `initialState` argument
initialState,
reducers: {
increment: state => {
state.value += 1
},
decrement: state => {
state.value -= 1
},
// Use the PayloadAction type to declare the contents of `action.payload`
incrementByAmount: (state, action: PayloadAction<number>) => {
state.value += action.payload
}
}
})

export const { increment, decrement, incrementByAmount } = counterSlice.actions

// Other code such as selectors can use the imported `RootState` type
export const selectCount = (state: RootState) => state.counter.value

export default counterSlice.reducer

生成されたアクションクリエーターは、リデューサー用に指定したPayloadAction<T>型に基づいて、payload引数を受け入れるよう正しく型付けされます。例えば、incrementByAmountは引数としてnumberを要求します。

場合によってはTypeScriptが初期状態の型を不必要に厳密化することがあります。そのような場合、変数の型を宣言する代わりにasを使用して初期状態をキャストすることで回避できます:

// Workaround: cast state instead of declaring variable type
const initialState = {
value: 0
} as CounterState

コンポーネントでの型付きフックの使用

コンポーネントファイルでは、React-Reduxの標準フックではなく、事前に型定義されたフックをインポートしてください。

features/counter/Counter.tsx
import React from 'react'

import { useAppSelector, useAppDispatch } from 'app/hooks'

import { decrement, increment } from './counterSlice'

export function Counter() {
// The `state` arg is correctly typed as `RootState` already
const count = useAppSelector(state => state.counter.value)
const dispatch = useAppDispatch()

// omit rendering logic
}

完全なカウンターアプリの例

以下は完全なTypeScriptカウンターアプリケーションの実行可能なCodeSandboxです:

次のステップ

すべての主要な機能をカバーする完全な「Redux Essentials」チュートリアルを通すことをお勧めします。Redux Toolkitに含まれる主要なパーツ、解決する問題、実践的なアプリケーション構築方法を学べます。

また「Redux Fundamentals」チュートリアルを読むことで、Reduxの動作原理、Redux Toolkitの役割、正しい使用方法を完全に理解できます。

最後に、Redux ToolkitのAPIをTypeScriptで使用する方法の詳細については、「TypeScriptでの使用法」ページを参照してください。