MDX — это расширение Markdown, позволяющее использовать JSX внутри Markdown-документов. Важно правильно управлять типами компонентов, чтобы избежать ошибок во время компиляции и обеспечить корректную интеграцию с TypeScript.
MDX-файлы обрабатываются как React-компоненты. Это означает, что
каждый элемент Markdown, включая заголовки, списки и параграфы, можно
переопределить через компоненты. Для типизации этих
компонентов используется интерфейс MDXProviderComponents из
пакета @mdx-js/react.
import { MDXProviderComponents } from '@mdx-js/react';
const components: MDXProviderComponents = {
h1: (props) => <h1 style={{ color: 'red' }} {...props} />,
p: (props) => <p style={{ fontSize: '16px' }} {...props} />,
};
Здесь MDXProviderComponents обеспечивает строгую
типизацию ключей (теги Markdown) и их пропсов. Ключи должны
соответствовать стандартным тегам HTML или пользовательским компонентам,
а пропсы — JSX-параметрам этих компонентов.
Каждый стандартный Markdown-элемент можно заменить пользовательским компонентом. Типизация позволяет указать точный интерфейс для каждого компонента:
interface CustomHeadingProps {
children: React.ReactNode;
level: 1 | 2 | 3 | 4 | 5 | 6;
}
const H: React.FC<CustomHeadingProps> = ({ children, level }) => {
const Tag = `h${level}` as keyof JSX.IntrinsicElements;
return <Tag>{children}</Tag>;
};
const components: MDXProviderComponents = {
h1: (props) => <H level={1} {...props} />,
h2: (props) => <H level={2} {...props} />,
};
Такой подход гарантирует, что при ошибочном использовании заголовка с неподдерживаемым уровнем TypeScript выдаст предупреждение.
MDX позволяет добавлять полностью кастомные компоненты, которые можно использовать прямо в Markdown:
interface AlertProps {
type: 'success' | 'error' | 'info';
children: React.ReactNode;
}
const Alert: React.FC<AlertProps> = ({ type, children }) => (
<div className={`alert alert-${type}`}>{children}</div>
);
const components: MDXProviderComponents = {
Alert, // теперь можно использовать <Alert> внутри MDX
};
Типизация здесь помогает сразу видеть ошибки при неверном
использовании пропсов (type="warning" будет ошибкой, так
как тип отсутствует в интерфейсе).
Можно объединять стандартные HTML-компоненты и пользовательские через
MDXComponents:
import { MDXComponents } from 'mdx/types';
interface CustomComponents extends MDXComponents {
Alert: React.FC<AlertProps>;
}
const components: CustomComponents = {
h1: (props) => <h1 style={{ color: 'blue' }} {...props} />,
Alert,
};
Использование интерфейса CustomComponents обеспечивает
строгую проверку типов не только для стандартных тегов, но и для новых
компонентов, добавленных в проект.
MDX позволяет указывать базовые пропсы для компонентов, чтобы избежать дублирования кода в каждом вызове:
const DefaultParagraph: React.FC<React.HTMLAttributes<HTMLParagraphElement>> = (props) => (
<p style={{ lineHeight: '1.6', marginBottom: '1em' }} {...props} />
);
const components: MDXProviderComponents = {
p: DefaultParagraph,
};
Для компонентов, принимающих children, рекомендуется
использовать React.ReactNode или
React.ReactElement в зависимости от того, требуется ли
строгая вложенность:
interface CardProps {
title: string;
children: React.ReactNode;
}
const Card: React.FC<CardProps> = ({ title, children }) => (
<div className="card">
<h3>{title}</h3>
<div>{children}</div>
</div>
);
React.ReactNode позволяет передавать любой контент:
текст, элементы JSX, массивы элементов.
MDX-файлы могут быть импортированы как React-компоненты, если настроена декларация модулей:
declare module '*.mdx' {
let MDXComponent: (props: any) => JSX.Element;
export default MDXComponent;
}
Можно усилить типизацию, указав пропсы для всех MDX-файлов:
declare module '*.mdx' {
import { MDXProviderComponents } from '@mdx-js/react';
interface MDXProps {
components?: MDXProviderComponents;
}
const MDXComponent: React.FC<MDXProps>;
export default MDXComponent;
}
Это позволяет передавать компоненты через components в
MDX без потери типизации.
MDXProviderComponents или расширять
его интерфейсы для пользовательских компонентов.children и все props для предсказуемости
поведения..mdx файлов, чтобы TypeScript
понимал структуру и пропсы.Эта система типизации обеспечивает безопасную работу с MDX и интеграцию с React, предотвращая ошибки еще на этапе компиляции и облегчая поддержку больших проектов.