Перейти к основному содержимому
Неофициальный Бета-перевод

Эта страница переведена PageTurner AI (бета). Не одобрена официально проектом. Нашли ошибку? Сообщить о проблеме →

Быстрый старт с Redux Toolkit и TypeScript

Что вы узнаете
  • Как настроить и использовать Redux Toolkit и React-Redux с TypeScript
Предварительные требования

Введение

Добро пожаловать в руководство по быстрому старту с Redux Toolkit и TypeScript! В этом кратком руководстве показано, как использовать TypeScript с Redux Toolkit и React-Redux.

Эта страница посвящена только настройке аспектов TypeScript. Объяснения, что такое Redux, как он работает, и полные примеры использования Redux Toolkit смотрите в руководствах из раздела "Индекс руководств".

Redux Toolkit уже написан на TypeScript, поэтому его типовые определения встроены.

React Redux также написан на TypeScript начиная с версии 8 и включает собственные определения типов.

Шаблон Redux+TS для Create-React-App содержит рабочий пример этих паттернов с предварительной настройкой.

Настройка проекта

Определение типов Root State и Dispatch

Для API configureStore из Redux Toolkit обычно не требуются дополнительные типизации. Однако рекомендуется извлечь типы RootState и Dispatch, чтобы на них можно было ссылаться при необходимости. Вывод этих типов из самого хранилища гарантирует их корректное обновление при добавлении новых срезов состояния или изменении настроек middleware.

Поскольку это типы, их можно безопасно экспортировать напрямую из файла настройки хранилища (например, 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

Создание типизированных хуков

Хотя можно импортировать типы RootState и AppDispatch в каждый компонент, лучше создать типизированные версии хуков useDispatch и useSelector для использования в приложении. Это важно по нескольким причинам:

  • Для useSelector это избавляет от необходимости каждый раз указывать (state: RootState)

  • Для useDispatch: стандартный тип Dispatch не знает о thunk'ах. Для корректной отправки thunk'ов необходимо использовать специальный тип AppDispatch из хранилища, который включает типы thunk-middleware, и использовать его вместе с 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 в каждом case reducer.

Все генерируемые действия должны определяться с использованием типа PayloadAction<T> из Redux Toolkit, который принимает тип поля 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

Созданные генераторы действий будут корректно типизированы для приёма аргумента payload на основе типа PayloadAction<T>, указанного для редюсера. Например, incrementByAmount требует аргумент типа number.

В некоторых случаях TypeScript может излишне ужесточить тип начального состояния. Если это произошло, вы можете обойти это приведением типа initial state через 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
}

Полный пример приложения-счётчика

Полное TS-приложение со счётчиком в работающем CodeSandbox:

Что дальше?

Рекомендуем пройти полный учебник «Redux Essentials», который охватывает все ключевые компоненты Redux Toolkit, решаемые ими проблемы и их применение в реальных приложениях.

Также полезно ознакомиться с учебником «Redux Fundamentals», который даст полное понимание работы Redux, функционала Redux Toolkit и правил его использования.

Дополнительные подробности об использовании API Redux Toolkit с TypeScript см. на странице «Использование с TypeScript».