Типизация компонентов

В библиотеке MUI (Material-UI) типизация компонентов играет ключевую роль при использовании TypeScript. Она обеспечивает строгий контроль над пропсами компонентов, предотвращает ошибки во время компиляции и повышает удобство автодополнения в редакторах кода.


1. Базовые принципы типизации

Каждый компонент MUI является React-компонентом с заранее определёнными типами пропсов. Например, компонент Button имеет собственный интерфейс пропсов ButtonProps:

import Button, { ButtonProps } from '@mui/material/Button';

const MyButton: React.FC<ButtonProps> = (props) => <Button {...props} />;
  • ButtonProps включает стандартные HTML-пропсы (onClick, className, style) и специфичные для MUI (variant, color, size).
  • Использование типизированных пропсов предотвращает передачу недопустимых значений, например:
<Button color="pink" /> // Ошибка: тип "pink" не входит в Color

2. Наследование HTML-пропсов

MUI компоненты обычно расширяют стандартные HTML-элементы. Например:

  • Button → расширяет ButtonHTMLAttributes<HTMLButtonElement>
  • TextField → расширяет InputHTMLAttributes<HTMLInputElement>

Это позволяет использовать стандартные пропсы HTML вместе с MUI-специфичными:

<TextField
  placeholder="Введите текст"
  required
  variant="outlined"
  color="primary"
/>

3. Переопределение типа корневого элемента (component prop)

Многие компоненты MUI поддерживают проп component, который позволяет изменять базовый HTML-элемент:

import { Button } from '@mui/material';

<Button component="a" href="/home" variant="contained">
  Ссылка-кнопка
</Button>

Типизация здесь корректно учитывает HTML-атрибуты нового элемента (href для <a> вместо onClick для <button>).

Для пользовательских компонентов можно передавать свои типы:

interface LinkProps {
  to: string;
}

const MyLink: React.FC<LinkProps> = ({ to, children }) => <a href={to}>{children}</a>;

<Button component={MyLink} to="/dashboard">
  На дашборд
</Button>

MUI автоматически выводит правильные пропсы для MyLink благодаря дженерикам.


4. Дженерики в типизации компонентов

Многие компоненты MUI используют TypeScript дженерики, чтобы обеспечить строгую типизацию в зависимости от варианта компонента или типа элемента. Пример: TextField с кастомным InputProps:

import TextField, { TextFieldProps } from '@mui/material/TextField';

interface CustomInputProps {
  maxLength: number;
}

const fieldProps: TextFieldProps<CustomInputProps> = {
  InputProps: {
    maxLength: 10
  },
  variant: 'outlined'
};

Дженерики позволяют:

  • Уточнять типы пропсов
  • Передавать кастомные интерфейсы для вложенных элементов (InputProps, SelectProps и др.)
  • Сохранять автокомплит и строгую проверку

5. Стилизация и типизация

MUI предлагает несколько способов стилизации компонентов, каждый из которых имеет собственную типизацию.

a) sx prop

SxProps поддерживает объекты с заранее определёнными CSS-свойствами:

<Box sx={{ color: 'primary.main', p: 2, borderRadius: 1 }}>
  Контент
</Box>

Типизация обеспечивает:

  • Подсказки по доступным цветам темы (primary.main, secondary.light)
  • Проверку корректности CSS-свойств (fontWeight, margin, display)

b) styled API

import { styled } from '@mui/material/styles';
import Button from '@mui/material/Button';

const MyStyledButton = styled(Button)<{ rounded: boolean }>(
  ({ theme, rounded }) => ({
    borderRadius: rounded ? theme.spacing(2) : theme.shape.borderRadius,
    padding: theme.spacing(1, 3),
  })
);
  • <{ rounded: boolean }> – определяет кастомный проп, типизированный TypeScript.
  • theme автоматически типизирован и предоставляет все значения темы (palette, spacing, typography).

c) makeStyles и useStyles (legacy)

import { makeStyles } from '@mui/styles';

const useStyles = makeStyles((theme) => ({
  root: {
    backgroundColor: theme.palette.primary.main,
  },
}));

С TypeScript нужно явно типизировать theme, чтобы избежать ошибок при доступе к палитре или типографике.


6. Пользовательские компоненты с MUI типизацией

Для создания обёрток над MUI компонентами важно использовать правильные дженерики:

import { Button, ButtonProps } from '@mui/material';

interface ExtraProps {
  loading: boolean;
}

const LoadingButton: React.FC<ButtonProps & ExtraProps> = ({ loading, ...props }) => (
  <Button {...props} disabled={loading}>
    {loading ? 'Загрузка...' : props.children}
  </Button>
);
  • Объединение интерфейсов через & позволяет сохранять все стандартные пропсы MUI.
  • Любые новые пропсы (loading) строго проверяются TypeScript.

7. Советы по безопасной типизации

  • Всегда импортировать пропсы компонента напрямую из MUI (ButtonProps, TextFieldProps).
  • Использовать дженерики для вложенных элементов (component, InputProps, SelectProps).
  • Для кастомных обёрток объединять типы через & или extends.
  • При работе со стилями использовать sx или styled для строгой типизации CSS и темы.

Типизация компонентов MUI позволяет писать предсказуемый, безопасный и автодополняемый код, что особенно важно в больших проектах на TypeScript. Она охватывает все аспекты: от стандартных HTML-пропсов до сложных кастомных компонентов с темой и стилями.