Решение проблем с TypeScript

Chakra UI полностью совместим с TypeScript, однако при использовании его компонентов могут возникать сложности с типами, особенно при расширении компонентов, работе с системными пропсами или создании собственных UI-компонентов на основе Box и Flex.

Ключевой момент: все компоненты Chakra UI имеют строго определённые пропсы, соответствующие системе стилей и функциональности библиотеки.

Использование системных пропсов с типами

Компоненты Chakra UI поддерживают системные пропсы (margin, padding, color, fontSize и др.). В TypeScript эти пропсы строго типизированы через интерфейсы SystemProps и ResponsiveValue.

Пример корректного использования:

import { Box } from "@chakra-ui/react";

const StyledBox: React.FC = () => (
  <Box 
    p={4}        // padding
    m={{ base: 2, md: 4 }}  // responsive margin
    bg="teal.500"
    color="white"
  >
    Пример Box с системными пропсами
  </Box>
);

Здесь p и m имеют тип ResponsiveValue<string | number>, что позволяет задавать как фиксированные значения, так и адаптивные через объект base/md/lg.

Расширение компонентов и корректная типизация

При создании пользовательских компонентов на основе Chakra UI важно правильно типизировать пропсы. Наиболее универсальный подход — использовать ComponentProps или ChakraProps из @chakra-ui/react.

import { Button, ChakraProps } from "@chakra-ui/react";

interface CustomButtonProps extends ChakraProps {
  isLoading?: boolean;
}

const CustomButton: React.FC<CustomButtonProps> = ({ isLoading, ...props }) => (
  <Button {...props} isLoading={isLoading}>
    Кнопка
  </Button>
);

Использование ChakraProps гарантирует, что все системные пропсы будут корректно типизированы, а isLoading добавлен как пользовательский пропс.

Проблемы с ref и forwardRef

Некорректная работа с ref часто возникает при обёртке компонентов Chakra. Для сохранения типизации и корректной работы ref необходимо использовать forwardRef:

import { forwardRef } from "react";
import { Input, InputProps } from "@chakra-ui/react";

const CustomInput = forwardRef<HTMLInputElement, InputProps>((props, ref) => (
  <Input ref={ref} {...props} />
));

Использование forwardRef позволяет TypeScript понимать тип ref и передавать его корректно в родительский компонент.

Типизация theme и расширение глобальной темы

Chakra UI позволяет расширять стандартную тему через extendTheme. При этом TypeScript требует правильного определения интерфейсов для новых цветов, шрифтов и размеров:

import { extendTheme, ThemeConfig, ThemeOverride } from "@chakra-ui/react";

const customTheme = extendTheme({
  colors: {
    brand: {
      50: "#f5faff",
      500: "#3182ce",
      900: "#1a365d",
    },
  },
  fonts: {
    heading: "Montserrat, sans-serif",
    body: "Inter, sans-serif",
  },
});

type CustomTheme = typeof customTheme;

Расширение глобального theme через declare module "@chakra-ui/react" позволяет TypeScript корректно понимать новые свойства и предотвращает ошибки при обращении к несуществующим ключам.

import "@chakra-ui/react";

declare module "@chakra-ui/react" {
  export interface Theme {
    colors: {
      brand: {
        50: string;
        500: string;
        900: string;
      };
    };
  }
}

Проблемы с компонентами, принимающими children

Компоненты вроде Box или Flex по умолчанию уже типизированы для React children. Ошибки возникают при создании собственных компонентов, где children могут быть обязательными или специфическими.

Пример корректной типизации:

interface CardProps extends ChakraProps {
  title: string;
  children: React.ReactNode;
}

const Card: React.FC<CardProps> = ({ title, children, ...props }) => (
  <Box p={4} shadow="md" borderWidth="1px" {...props}>
    <Box fontWeight="bold">{title}</Box>
    {children}
  </Box>
);

Работа с асинхронными компонентами и lazy-loading

При использовании React.lazy с Chakra UI важно сохранять типизацию пропсов:

import { Suspense, lazy } from "react";
import { Spinner } from "@chakra-ui/react";

const LazyComponent = lazy(() => import("./SomeChakraComponent"));

const Wrapper = () => (
  <Suspense fallback={<Spinner />}>
    <LazyComponent p={4} />
  </Suspense>
);

p={4} корректно типизируется через ChakraProps, предотвращая ошибки при динамической загрузке компонента.

Частые ошибки TypeScript и пути их решения

  1. Ошибка: Type ‘{ children: string; bg: string; }’ is not assignable to type…

    • Обычно возникает из-за отсутствия расширения пропсов через ChakraProps. Решение: наследовать интерфейс от ChakraProps или использовать ComponentProps<typeof Box>.
  2. Ошибка при работе с ref

    • Решение: применять forwardRef с правильными дженериками для HTML-элементов.
  3. Ошибки при расширении темы

    • Решение: использовать declare module "@chakra-ui/react" и точно типизировать новые ключи темы.
  4. Ошибки с responsive-пропсами

    • Тип ResponsiveValue должен включать все используемые типы значений: number | string | Array<number | string> | { base?: T; sm?: T; md?: T; lg?: T; xl?: T }.

Использование этих подходов обеспечивает строгую типизацию и предотвращает большинство ошибок TypeScript при работе с Chakra UI, одновременно сохраняя гибкость компонентов и поддержку системы стилей.