JavaRush /Курсы /Модуль 3: React /Лекция 33: Типизация HOC и параметров с TypeScript

Лекция 33: Типизация HOC и параметров с TypeScript

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

Основы типизации HOC

Начнём с чего-то простого: напишем HOC, который добавляет новые пропсы к обёрнутому компоненту. Например, HOC, который добавляет текущую дату.

import React from 'react';

// Интерфейс для дополнительных пропсов
interface WithDateProps {
  currentDate: string;
}

// HOC, добавляющий `currentDate` в компонент
function withDate<P>(WrappedComponent: React.ComponentType<P & WithDateProps>) {
  return (props: P) => {
    const currentDate = new Date().toISOString();

    return <WrappedComponent {...props} currentDate={currentDate} />;
  };
}

// Пример использования
interface OriginalProps {
  name: string;
}

const OriginalComponent: React.FC<OriginalProps & WithDateProps> = ({ name, currentDate }) => (
  <p>
    Привет, {name}! Сейчас {currentDate}.
  </p>
);

const EnhancedComponent = withDate(OriginalComponent);

Что здесь происходит?

  1. Мы определили интерфейс WithDateProps для пропсов, которые добавляет наш HOC.
  2. HOC принимает компонент через параметр WrappedComponent.
  3. Мы добавили новые пропсы currentDate и передали все оригинальные пропсы дальше через {...props}.

Типизация HOC

Обратите внимание на <P & WithDateProps>. Здесь:

  • P — это тип пропсов оригинального компонента.
  • Мы говорим, что обёрнутый компонент принимает как оригинальные пропсы, так и добавленные WithDateProps.

Удаление лишних пропсов

Иногда HOC добавляет пропсы, которые не должны быть видимы для внешнего мира. Например, пропсы, которые используются только внутри HOC, не должны просачиваться наружу.

Давайте доработаем предыдущий пример:

function withDate<P>(WrappedComponent: React.ComponentTyp<P & WithDateProps>) {
  return (props: P) => {
    const currentDate = new Date().toISOString();

    // Удаляем проброс лишних пропсов
    return <WrappedComponent {...props} currentDate={currentDate} />;
  };
}

// Тип обёрнутого компонента
type WrappedComponentType = typeof OriginalComponent;

// Оригинал и добавленные пропсы остаются строго типизированными
const EnhancedComponent = withDate(OriginalComponent);

В этом примере HOC не пробрасывает свои внутренние данные наружу, что делает интерфейс компонента более гибким.

Типизация HOC с пропсами: сложный случай

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

import React from 'react';

// Интерфейс для пропсов HOC
interface WithAuthProps {
  isAuthenticated: boolean;
}

// HOC, добавляющий условное отображение
function withAuth<P>(WrappedComponent: React.ComponentType<P>) {
  return ({ isAuthenticated, ...props }: P & WithAuthProps) => {
    if (!isAuthenticated) {
      return <p>Доступ запрещён</p>;
    }

    return <WrappedComponent {...props as P} />;
  };
}

// Пример использования
interface UserProps {
  username: string;
}

const UserComponent: React.FC<UserProps> = ({ username }) => (
  <p>Добро пожаловать, {username}!</p>
);

const AuthenticatedUserComponent = withAuth(UserComponent);

Что этот код делает?

  1. HOC принимает пропсу isAuthenticated и решает, отображать ли компонент.
  2. Мы используем оператор TypeScript as P, чтобы явно указать, что остальные пропсы ...props соответствуют типу P.

Примеры сложной типизации

Полиморфизм в HOC

Иногда нам нужны HOC, которые будут работать с разными компонентами и их типами пропсов. Это делается через обобщённые типы generics.

Например, HOC для логгирования пропсов:

function withLogger<P>(WrappedComponent: React.ComponentType<P>) {
  return (props: P) => {
    console.log('Пропсы:', props);
    return <WrappedComponent {...props} />;
  };
}

// Пример использования
const LoggedOriginalComponent = withLogger(OriginalComponent);

Этот HOC универсально работает с любым компонентом, независимо от его пропсов. Использование дженериков P обеспечивает гибкость и безопасность.

Разбор типичных ошибок и подходов

Проблема 1: неправильный порядок пропсов

Иногда при типизации HOC вы можете забыть пересечение типов P & ExtraProps и просто указать P. Это может привести к ошибкам из-за отсутствия новых пропсов у обёрнутого компонента.

Правильно:
React.ComponentType<P & ExtraProps>.

Неправильно:
React.ComponentType<P>.

Проблема 2: типы пропсов теряются

Если HOC не передаёт оригинальные пропсы, это может вызвать неожиданные ошибки. Убедитесь, что вы занимаете только те пропсы, которые действительно нужны вашему HOC, и не забывайте пробрасывать остальные через {...props}.

Проблема 3: сложность при сильной вложенности

При работе с несколькими HOC типизация может стать сложной. Используйте React.ComponentProps<typeof YourComponent> для автоматического извлечения типа пропсов из существующего компонента.

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