Парсер для TypeScript

Статический анализ кода в ESLint опирается на промежуточное представление исходного текста — абстрактное синтаксическое дерево (AST). Парсер выполняет преобразование исходного JavaScript- или TypeScript-кода в структуру, пригодную для анализа правилами линтера. Без корректного парсера невозможна работа ни базовых синтаксических проверок, ни правил, использующих типизацию.

В стандартной конфигурации ESLint применяется парсер Espree, ориентированный на JavaScript. TypeScript расширяет синтаксис языка дополнительными конструкциями: типами, интерфейсами, перечислениями, generics и модификаторами доступа. Espree не способен корректно интерпретировать эти конструкции, что делает необходимым использование специализированного парсера.

Ограничения стандартного JavaScript-парсера

Espree формирует AST на основе спецификации ECMAScript, однако TypeScript включает элементы, отсутствующие в стандарте Jav * aScript:

  • аннотации типов (: string, : number)
  • интерфейсы и type aliases
  • enum-конструкции
  • generics (Array<T>)
  • namespace и module augmentation
  • модификаторы доступа (private, protected, public)
  • реализация интерфейсов в классах

Попытка анализа TypeScript-кода стандартным парсером приводит к синтаксическим ошибкам или потере информации о типах. Это ограничивает возможности правил ESLint, особенно тех, которые зависят от семантики типов.

Парсер @typescript-eslint/parser

Основным решением для интеграции TypeScript в ESLint является @typescript-eslint/parser. Этот парсер преобразует TypeScript-код в ESTree-совместимый AST с расширениями, позволяющими учитывать типовую систему языка.

Ключевые свойства:

  • поддержка полного синтаксиса TypeScript
  • совместимость с ESLint rule API
  • интеграция с TypeScript Compiler API
  • возможность построения type-aware анализа

Парсер не заменяет TypeScript-компилятор, а использует его внутренние механизмы для извлечения информации о типах и структуре кода.

Базовая конфигурация парсера

Подключение парсера осуществляется через конфигурацию ESLint:

// eslint.config.js (Flat Config)
import tsParser from "@typescript-eslint/parser";

export default [
  {
    files: ["**/*.ts", "**/*.tsx"],
    languageOptions: {
      parser: tsParser,
      parserOptions: {
        ecmaVersion: "latest",
        sourceType: "module"
      }
    }
  }
];

В legacy-конфигурации:

module.exports = {
  parser: "@typescript-eslint/parser",
  parserOptions: {
    ecmaVersion: 2022,
    sourceType: "module"
  }
};

parserOptions и их значение

ecmaVersion

Определяет версию ECMAScript, используемую при разборе. В контексте TypeScript обычно устанавливается значение latest, что позволяет поддерживать актуальный синтаксис JavaScript.

sourceType

Задает режим модулей:

  • script — классический режим
  • module — поддержка import/export

Для TypeScript-проектов практически всегда используется module.

project

Ключевая опция для включения типо-зависимого анализа:

parserOptions: {
  project: "./tsconfig.json"
}

При указании project парсер подключает TypeScript Compiler API и формирует полноценную типовую модель проекта.

tsconfigRootDir

Используется для корректного разрешения относительных путей к tsconfig.json:

parserOptions: {
  project: "./tsconfig.json",
  tsconfigRootDir: __dirname
}

Type-aware linting

Type-aware linting — режим анализа, при котором ESLint получает доступ к типам переменных, выражений и функций. Это позволяет создавать правила, учитывающие семантику TypeScript, а не только синтаксис.

Примеры возможностей:

  • проверка вызовов методов с учетом типов
  • анализ небезопасных приведений типов
  • выявление лишних null/undefined проверок
  • контроль корректности generics

Включение type-aware анализа требует обязательного указания parserOptions.project.

Взаимодействие с TypeScript Compiler API

@typescript-eslint/parser использует внутренние механизмы TypeScript:

  • создание Program через ts.createProgram
  • анализ AST через ts.getSourceFile
  • извлечение type checker
  • построение symbol table

Результатом становится расширенный AST, который сохраняет совместимость с ESLint, но содержит дополнительные метаданные о типах.

Различия AST между JavaScript и TypeScript

TypeScript AST расширяет стандарт ESTree следующими элементами:

  • TypeAnnotation
  • TSInterfaceDeclaration
  • TSTypeAliasDeclaration
  • TSEnumDeclaration
  • TSAsExpression
  • NonNullExpression
  • TSModuleDeclaration

Эти узлы позволяют правилам ESLint различать синтаксические и семантические конструкции TypeScript.

Использование @typescript-eslint

Экосистема @typescript-eslint включает не только парсер, но и набор правил и утилит:

  • @typescript-eslint/eslint-plugin — набор правил
  • @typescript-eslint/parser — обработка AST
  • shared utilities для создания кастомных правил

Конфигурация:

import tsParser from "@typescript-eslint/parser";
import tsPlugin from "@typescript-eslint/eslint-plugin";

export default [
  {
    files: ["**/*.ts"],
    languageOptions: {
      parser: tsParser,
      parserOptions: {
        project: "./tsconfig.json"
      }
    },
    plugins: {
      "@typescript-eslint": tsPlugin
    },
    rules: {
      "@typescript-eslint/no-unused-vars": "error"
    }
  }
];

Производительность парсинга

Type-aware режим существенно увеличивает нагрузку:

  • создается TypeScript Program
  • выполняется анализ всего проекта
  • кеширование становится критически важным

Факторы влияния:

  • размер tsconfig
  • количество файлов в проекте
  • использование монорепозиториев
  • включение/исключение файлов через files и exclude

Для оптимизации применяются:

  • разделение конфигураций ESLint по пакетам
  • использование parserOptions.projectService (новые версии)
  • ограничение области анализа через overrides

projectService и современный подход

Современные версии @typescript-eslint поддерживают projectService, уменьшающий стоимость инициализации TypeScript Program:

parserOptions: {
  projectService: true
}

Механизм позволяет переиспользовать уже созданные сервисы анализа и снижать накладные расходы при linting больших кодовых баз.

Монорепозитории и парсер TypeScript

В монорепозиториях возникает проблема множественных tsconfig.json. Решения:

  • использование нескольких конфигураций ESLint
  • указание массива проектов:
parserOptions: {
  project: ["./packages/*/tsconfig.json"]
}
  • изоляция пакетов через overrides

Каждый пакет может иметь собственный TypeScript Program, что снижает конфликтность зависимостей типов.

JSX и TSX в парсере

TypeScript-парсер поддерживает JSX через расширение .tsx. Для корректной работы требуется:

parserOptions: {
  ecmaFeatures: {
    jsx: true
  }
}

JSX-узлы преобразуются в совместимые конструкции ESTree с сохранением TypeScript-типизации компонентов.

Частые проблемы конфигурации

Ошибка отсутствия project

При включении type-aware правил без project возникает ошибка:

  • невозможность создания Program
  • отключение правил, требующих типы

Конфликты версий TypeScript

Несовместимость версий typescript и @typescript-eslint/parser приводит к:

  • ошибкам анализа AST
  • некорректной типизации
  • падению lint-процесса

Проблемы с путями tsconfig

Неправильный tsconfigRootDir приводит к:

  • невозможности найти файлы проекта
  • частичному анализу кода
  • снижению точности правил

Связь парсера и правил ESLint

Парсер является фундаментом для выполнения правил:

  • синтаксические правила используют AST напрямую
  • семантические правила используют type checker
  • кастомные правила получают доступ к контексту TypeScript

Таким образом, качество парсинга напрямую определяет точность линтинга и полноту анализа кода в TypeScript-проектах