Обработка Markdown в TypeScript: библиотеки, парсеры и практическое применение

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Работа с Markdown в TypeScript: от парсинга до кастомных плагинов

Markdown остаётся одним из самых популярных языков разметки для документации, блогов и образовательных платформ. При разработке на TypeScript возникает необходимость не только отображать Markdown, но и гибко управлять процессом его преобразования. В этой статье мы разберём три ключевые библиотеки, которые помогут вам интегрировать Markdown в ваш TypeScript-проект, и покажем, как создавать собственные расширения.

Почему TypeScript важен для работы с Markdown?

TypeScript добавляет строгую типизацию, что критически важно при обработке пользовательского контента. Вы точно знаете, какие данные приходят из Markdown-файлов, и можете избежать ошибок времени выполнения. Кроме того, TypeScript упрощает создание плагинов и middleware для парсеров.

Обзор популярных библиотек

  • marked — самый быстрый и простой парсер. Минимальная конфигурация, отличная производительность.
  • unified / remark — экосистема для синтаксического анализа. Позволяет создавать сложные цепочки преобразований (AST -> HTML -> React).
  • showdown — лёгкая альтернатива с поддержкой расширений, хорошо документирована.

Пример 1: Базовый парсинг с marked

Библиотека marked идеальна для быстрого старта. Установите её через npm:

npm install marked

Типы для TypeScript поставляются в комплекте. Пример использования:

import { marked } from 'marked';

const markdownContent = `# Привет, TypeScript!
Это **жирный текст** и `код`.
- Элемент списка
- Ещё один`;

const html = marked.parse(markdownContent);
console.log(html);
// Вывод: <h1>Привет, TypeScript!</h1>
// <p>Это <strong>жирный текст</strong> и <code>код</code>.</p>
// <ul><li>Элемент списка</li><li>Ещё один</li></ul>

Для асинхронной работы используйте marked.parseAsync(). Это полезно при загрузке файлов из сети.

Пример 2: Кастомный рендерер с типизацией

Иногда нужно изменить стандартное поведение. Например, добавить классы к ссылкам или обработать изображения. Создадим кастомный рендерер на TypeScript:

import { marked, Renderer } from 'marked';

interface CustomRenderer extends Renderer {
  link(href: string, title: string | null, text: string): string;
}

const renderer: Partial<CustomRenderer> = {
  link({ href, title, text }) {
    return `<a href="${href}" target="_blank" rel="noopener noreferrer" class="external-link">${text}</a>`;
  }
};

marked.use({ renderer });

const markdown = 'Посети [PythonLib](https://pythonlib.ru)';
const result = marked.parse(markdown);
// <a href="https://pythonlib.ru" target="_blank" class="external-link">PythonLib</a>

Тип Partial<CustomRenderer> гарантирует, что мы переопределяем только нужные методы.

Пример 3: Работа с AST через unified и remark

Если вам нужен полный контроль над структурой документа, используйте unified и remark. Установка:

npm install unified remark-parse remark-stringify remark-html

Пример парсинга в синтаксическое дерево (AST) и обратно:

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkStringify from 'remark-stringify';
import remarkHtml from 'remark-html';

const markdown = '# Заголовок\nЭто **важно**.';

const file = await unified()
  .use(remarkParse)      // Парсинг в AST
  .use(remarkStringify)  // Обратно в Markdown (для проверки)
  .process(markdown);

console.log(String(file)); // Исходный Markdown

const htmlFile = await unified()
  .use(remarkParse)
  .use(remarkHtml)       // Преобразование в HTML
  .process(markdown);

console.log(String(htmlFile)); // <h1>Заголовок</h1><p>Это <strong>важно</strong>.</p>

Вы можете вставлять свои плагины между remarkParse и remarkHtml, например, для подсветки кода или проверки ссылок.

Пример 4: Кастомный плагин для remark

Создадим плагин, который заменяет все ссылки на

Рекомендаций