Утилитарные типы

MDX (Markdown + JSX) представляет собой расширение стандартного Markdown, позволяющее интегрировать компоненты React напрямую в текст документации. Для эффективной работы с MDX необходима строгая типизация, особенно при использовании TypeScript. Утилитарные типы помогают создавать гибкие и безопасные структуры данных, облегчая работу с компонентами и контентом MDX.


Тип Props для компонентов MDX

В MDX каждый React-компонент может принимать пропсы. Для типизации этих пропсов используют встроенные утилитарные типы TypeScript:

type ComponentProps<T> = T extends React.ComponentType<infer P> ? P : never;
  • ComponentProps<T> извлекает тип пропсов компонента T.
  • Применение: позволяет точно определить, какие свойства ожидает компонент, и предотвращает ошибки на этапе компиляции.

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

import { Button } from './Button';

type ButtonProps = ComponentProps<typeof Button>;

const mdxContent: ButtonProps = {
  label: "Нажми меня",
  disabled: false
};

Такой подход исключает несовпадения типов между компонентом и его использованием в MDX.


Тип Partial

Утилита Partial<T> превращает все свойства типа T в необязательные:

interface AlertProps {
  message: string;
  type: 'info' | 'error' | 'success';
  duration: number;
}

const optionalAlert: Partial<AlertProps> = {
  message: "Привет"
};
  • Используется при создании гибких конфигураций компонентов MDX.
  • Полезно для дефолтных параметров: можно задать только часть свойств, а остальные использовать по умолчанию.

Тип Required

Противоположность Partial, делает все свойства обязательными:

interface TooltipProps {
  content?: string;
  position?: 'top' | 'bottom';
}

const tooltip: Required<TooltipProps> = {
  content: "Информация",
  position: "top"
};
  • Гарантирует, что все свойства компонента будут указаны.
  • Полезно для MDX-шаблонов, где критично наличие всех параметров для корректного рендеринга.

Тип Pick

Позволяет выбрать подмножество свойств типа:

interface CardProps {
  title: string;
  description: string;
  image: string;
  link: string;
}

type CardPreviewProps = Pick<CardProps, 'title' | 'image'>;

const preview: CardPreviewProps = {
  title: "Заголовок",
  image: "image.png"
};
  • Используется для создания упрощенных версий компонентов MDX.
  • Удобно для сниппетов или мини-превью без полного набора данных.

Тип Omit

Противоположность Pick, исключает указанные свойства:

type CardWithoutLink = Omit<CardProps, 'link'>;

const card: CardWithoutLink = {
  title: "Заголовок",
  description: "Описание",
  image: "image.png"
};
  • Применяется, когда часть пропсов управляется автоматически или недоступна для пользователя.
  • Полезно при интеграции компонентов MDX в разные контексты, где часть данных не требуется.

Тип Record

Позволяет создавать объектные структуры с фиксированными ключами и единым типом значений:

type MDXComponents = Record<'h1' | 'p' | 'code', React.ComponentType<any>>;

const components: MDXComponents = {
  h1: (props) => <h1 {...props} />,
  p: (props) => <p {...props} />,
  code: (props) => <pre {...props} />
};
  • Полезно для переопределения стандартных элементов Markdown в MDX.
  • Обеспечивает строгую типизацию карты компонентов.

Тип Readonly

Делает все свойства объекта доступными только для чтения:

interface Config {
  apiUrl: string;
  timeout: number;
}

const config: Readonly<Config> = {
  apiUrl: "https://api.example.com",
  timeout: 5000
};

// Ошибка: config.timeout = 1000;
  • Защищает конфигурации MDX-компонентов от непреднамеренного изменения.
  • Полезно для константных данных, таких как темы или глобальные настройки.

Сочетание утилитарных типов

MDX-проекты часто комбинируют утилитарные типы для сложных сценариев:

type EditableAlertProps = Partial<Omit<AlertProps, 'duration'>>;
  • Omit<AlertProps, 'duration'> исключает свойство duration.
  • Partial<...> делает оставшиеся свойства необязательными.
  • Позволяет создавать динамичные конфигурации для MDX-компонентов без потери контроля над типами.

Тип ReturnType

Позволяет извлечь тип возвращаемого значения функции:

function createButton(label: string) {
  return <button>{label}</button>;
}

type ButtonElement = ReturnType<typeof createButton>;
  • Используется для определения типа JSX-элементов в MDX.
  • Удобно при построении библиотек компонентов, где функция возвращает JSX-структуру, и требуется строгая типизация.

Примеры интеграции в MDX

import { Meta, Story } from '@storybook/react';
import { Button } from './Button';

type ButtonStoryProps = Partial<ComponentProps<typeof Button>>;

<Meta title="Components/Button" component={Button} />

<Story name="Primary">
  <Button label="Click me" />
</Story>
  • Использование ComponentProps гарантирует точность типов для пропсов.
  • Partial позволяет задавать только необходимые параметры для сторибука или документации.

Эти утилитарные типы формируют основу безопасного и масштабируемого подхода к работе с MDX в TypeScript. Их грамотное применение позволяет создавать гибкие компоненты, типизированные конфигурации и надежные интерфейсы, минимизируя ошибки и ускоряя разработку.