JavaRush /Курсы /Модуль 3: React /Типизация Thunk-функций с TypeScript

Типизация Thunk-функций с TypeScript

Модуль 3: React
7 уровень , 2 лекция
Открыта

Базовая структура Thunk

Прежде чем углубимся в типизацию, давайте вспомним, как выглядит базовый Thunk:

// Простой Thunk без типизации
export const fetchUserData = () => {
  return async (dispatch: any) => {
    const response = await fetch(`/api/users`);
    const data = await response.json();
    dispatch({ type: "SET_USER_DATA", payload: data });
  };
};

Как вы можете заметить, здесь используется dispatch для передачи данных в reducer. Однако в этом примере отсутствует типизация, из-за чего легко допустить ошибки. Давайте добавим немного волшебства TypeScript!

Типизация Thunk: первые шаги

Redux Toolkit предоставляет полезный тип ThunkAction из пакета redux-thunk, который позволяет описать типы Thunk-функций. Начнём с типизации нашего dispatch.

Типизация AppDispatch

dispatch — это центральная точка взаимодействия с нашим Redux-хранилищем. Чтобы типизировать dispatch, нам нужно описать, какие действия он может обрабатывать.

import { configureStore } from "@reduxjs/toolkit";
import { ThunkAction } from "redux-thunk";

// Типизация Redux Store
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

// Пример создания store
const store = configureStore({
  reducer: {
    // ваши редьюсеры
  },
});

Теперь мы можем типизировать dispatch в наших Thunk-функциях.

Типизация ThunkAction

Используем ThunkAction, чтобы описать структуру Thunk. Вот основные параметры, которые принимает ThunkAction:

  1. ReturnType: что вернёт наша функция (обычно это void).
  2. State: состояние Redux (наш RootState).
  3. ExtraThunkArg: дополнительные аргументы (редко используется, поэтому часто указываем unknown).
  4. BasicAction: базовый тип Redux Action.

Давайте посмотрим на типизированную Thunk-функцию:

import { ThunkAction } from "redux-thunk";
import { RootState } from "../store"; // Ваш типизированный стейт

type AppThunk<ReturnType = void> = ThunkAction<
  ReturnType,
  RootState,
  unknown,
  Action<string>
>;

export const fetchUserData = (): AppThunk => {
  return async (dispatch, getState) => {
    const response = await fetch(`/api/users`);
    const data = await response.json();
    dispatch({ type: "SET_USER_DATA", payload: data });
  };
};

Теперь, если вы передадите неверный тип данных в dispatch, TypeScript немедленно сигнализирует об ошибке.

Типизация API-ответов

Одной из главных причин использовать TypeScript с Redux Thunk является возможность типизации данных, которые ваша Thunk-функция получает от API. Давайте рассмотрим пример.

Описание интерфейса API-ответа

Предположим, что наш API возвращает следующую структуру данных пользователя:

{
  "id": 1,
  "name": "John Doe",
  "email": "john.doe@example.com"
}

Создадим интерфейс для этих данных:

interface User {
  id: number;
  name: string;
  email: string;
}

Использование интерфейса в Thunk

Теперь мы можем типизировать наш Thunk, чтобы TypeScript знал, какие данные мы ожидаем от API.

import { ThunkAction } from "redux-thunk";
import { RootState } from "../store";
import { Action } from "redux";

// Интерфейс для API-ответа
interface User {
  id: number;
  name: string;
  email: string;
}

type AppThunk = ThunkAction<void, RootState, unknown, Action<string>>;

export const fetchUserData = (): AppThunk => {
  return async (dispatch, getState) => {
    const response = await fetch(`/api/users`);
    const data: User[] = await response.json(); // Типизируем данные как массив пользователей
    dispatch({ type: "SET_USER_DATA", payload: data });
  };
};

Теперь, если API изменит структуру данных, TypeScript сообщит об этом заранее.

Типизация состояния (state) и действий (actions)

Давайте разберемся, как типизировать Redux-состояние и действия. Это основа для строгой типизации всего Redux-приложения.

Типизация состояния

Сначала определим интерфейс нашего состояния:

interface UserState {
  users: User[];
  isLoading: boolean;
  error: string | null;
}

Затем добавим это состояние в наш reducer:

const initialState: UserState = {
  users: [],
  isLoading: false,
  error: null,
};

export const userReducer = (state = initialState, action: UserActions): UserState => {
  switch (action.type) {
    case "SET_USER_DATA":
      return { ...state, users: action.payload };
    case "SET_LOADING":
      return { ...state, isLoading: action.payload };
    default:
      return state;
  }
};

Типизация действий

Определим интерфейсы для наших действий:

interface SetUserDataAction {
  type: "SET_USER_DATA";
  payload: User[];
}

interface SetLoadingAction {
  type: "SET_LOADING";
  payload: boolean;
}

type UserActions = SetUserDataAction | SetLoadingAction;

Теперь мы можем типизировать все действия в нашем приложении.

Практическое применение типизированных Thunk

Давайте соберём всё вместе и создадим типизированное приложение.

// actions.ts
export const fetchUserData = (): AppThunk => {
  return async (dispatch, getState) => {
    dispatch({ type: "SET_LOADING", payload: true });

    try {
      const response = await fetch(`/api/users`);
      const data: User[] = await response.json();
      dispatch({ type: "SET_USER_DATA", payload: data });
    } catch (error) {
      dispatch({ type: "SET_ERROR", payload: error.message });
    } finally {
      dispatch({ type: "SET_LOADING", payload: false });
    }
  };
};

Типичные ошибки

Не забывайте об основных проблемах, с которыми вы можете столкнуться:

  1. Вы можете забыть типизировать RootState или AppDispatch. Проверьте, чтобы store был корректно настроен.
  2. Если вы используете неправильные интерфейсы для API-ответа, TypeScript не сможет защитить вас от ошибок.
  3. Не используйте any — это уничтожает магию TypeScript.

На этом этапе вы готовы использовать типизированные Redux Thunk-функции в своих проектах. В будущем вы оцените, насколько TypeScript упрощает масштабирование и поддержку вашего кода!

1
Задача
Модуль 3: React, 7 уровень, 2 лекция
Недоступна
Простая типизация Thunk-функции
Простая типизация Thunk-функции
1
Задача
Модуль 3: React, 7 уровень, 2 лекция
Недоступна
Типизация данных из API
Типизация данных из API
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ