MUI (Material-UI) предоставляет мощный набор инструментов для создания компонентов с полной поддержкой TypeScript. Ключевая задача при разработке кастомных компонентов — корректная типизация пропсов, что позволяет сохранять совместимость с системами автокомплита, предотвращать ошибки и использовать преимущества строгой проверки типов.
При создании кастомного компонента на основе MUI важно учитывать два аспекта:
Пример базового компонента с типизацией:
import React from 'react';
import Button, { ButtonProps } from '@mui/material/Button';
interface CustomButtonProps extends ButtonProps {
highlight?: boolean;
}
const CustomButton: React.FC<CustomButtonProps> = ({ highlight, ...props }) => {
return (
<Button
{...props}
style={{
backgroundColor: highlight ? 'yellow' : undefined,
...props.style,
}}
>
{props.children}
</Button>
);
};
export default CustomButton;
Объяснение ключевых моментов:
extends ButtonProps позволяет автоматически
использовать все свойства стандартного MUI Button (variant,
color, size и т.д.).highlight добавляется отдельно и учитывается
при рендере.{...props} обеспечивает передачу всех
стандартных пропсов внутрь компонента MUI.OverridableComponent для расширяемостиMUI предоставляет тип OverridableComponent, который
позволяет создавать компоненты с динамическим component
prop, что особенно важно для элементов вроде кнопок, ссылок или
карточек.
Пример:
import { OverridableComponent, OverrideProps } from '@mui/material/OverridableComponent';
import { ButtonTypeMap } from '@mui/material/Button';
interface CustomButtonTypeMap<P = {}, D extends React.ElementType = 'button'> {
props: P & { highlight?: boolean };
defaultComponent: D;
}
type CustomButtonProps<
D extends React.ElementType = CustomButtonTypeMap['defaultComponent'],
P = {}
> = OverrideProps<CustomButtonTypeMap<P, D>, D>;
const CustomButton: OverridableComponent<CustomButtonTypeMap> = (props) => {
const { highlight, ...rest } = props;
return <Button {...rest} style={{ backgroundColor: highlight ? 'yellow' : undefined }} />;
};
Преимущества:
component="a" или любого другого тега без
потери типизации.styled и типизация стилейПри создании кастомных компонентов с использованием
styled важно правильно типизировать пропсы, влияющие на
стили:
import { styled } from '@mui/material/styles';
import Button, { ButtonProps } from '@mui/material/Button';
interface StyledButtonProps extends ButtonProps {
highlight?: boolean;
}
const StyledButton = styled(Button, {
shouldForwardProp: (prop) => prop !== 'highlight',
})<StyledButtonProps>(({ highlight, theme }) => ({
backgroundColor: highlight ? theme.palette.warning.main : undefined,
color: highlight ? theme.palette.common.black : undefined,
}));
export default StyledButton;
Особенности:
shouldForwardProp предотвращает передачу нестандартных
пропсов в DOM.<StyledButtonProps>
обеспечивает корректную проверку типов для пользовательских
свойств.Для компонентов, которые принимают функции обратного вызова с определёнными типами, TypeScript позволяет точно описывать сигнатуры:
interface CustomInputProps {
onValueChange?: (value: string, isValid: boolean) => void;
}
const CustomInput: React.FC<CustomInputProps> = ({ onValueChange }) => {
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.target.value;
const isValid = value.length > 0;
onValueChange?.(value, isValid);
};
return <input type="text" onCha nge={handleChange} />;
};
?) повышает
гибкость без потери безопасности типов.Иногда требуется комбинировать несколько компонентов с разными типами пропсов. Для этого удобно использовать пересечение типов:
interface ExtraProps {
tooltip?: string;
}
type ComposedButtonProps = CustomButtonProps & ExtraProps;
const ComposedButton: React.FC<ComposedButtonProps> = ({ tooltip, ...props }) => (
<div title={tooltip}>
<CustomButton {...props} />
</div>
);
&) объединяет свойства
нескольких интерфейсов.extends для наследования стандартных MUI
пропсов.OverridableComponent.<Props> и
shouldForwardProp.Эти принципы позволяют создавать надёжные и масштабируемые кастомные компоненты MUI с полной поддержкой TypeScript, обеспечивая предсказуемость и безопасность кода.