«React refers to a UMD global»: как TypeScript сходит с ума

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

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

Начать курс

Введение: когда компилятор говорит «нет»

Вы открываете свой любимый редактор, пишете несколько строк кода на TypeScript, запускаете сборку — и вдруг видите это: 'React' refers to a UMD global, but the current file is a module. Если вы когда-нибудь сталкивались с этой ошибкой, вы знаете, насколько она может быть обескураживающей. Вроде бы всё правильно: импорт есть, React установлен, но компилятор упрямо отказывается понимать, что вы от него хотите.

Эта ошибка — не просто случайный баг. Она раскрывает глубокие механизмы работы TypeScript, систем сборки и модульных форматов. В этой статье мы не просто покажем, как её исправить. Мы заглянем «под капот» и разберёмся, почему возникает ошибка React refers to a UMD global, как TypeScript различает UMD и ESM, и как правильно настроить ваш проект, чтобы забыть о ней навсегда.

Статья ориентирована на разработчиков, которые уже знакомы с React и TypeScript, но хотят понять внутреннюю кухню. Готовы? Поехали!

Что такое UMD и почему TypeScript о нём знает?

Прежде чем разбирать ошибку, давайте вспомним, что такое модульные форматы в JavaScript. Когда вы пишете import React from 'react', TypeScript должен понять, откуда берётся этот код и как его использовать. Существует несколько стандартов:

  • ESM (ECMAScript Modules) — современный стандарт, использующий import/export.
  • CommonJS — формат Node.js с require/module.exports.
  • UMD (Universal Module Definition) — гибрид, который работает и в браузере (через глобальные переменные), и в Node.js (через модули).

React распространяется в нескольких форматах, включая UMD. Когда вы устанавливаете React через npm, вы получаете ESM-версию (например, index.js с export default). Но старые версии или некоторые сборки могут использовать UMD, где React доступен как глобальная переменная window.React.

TypeScript анализирует файлы деклараций типов (.d.ts). Для React это пакет @types/react. Внутри него есть объявление, которое указывает: «React доступен как UMD global». Когда TypeScript видит, что ваш файл помечен как модуль (например, содержит import или export), он начинает путаться: «Вы импортируете React, но в декларации сказано, что это глобал. А файл — модуль. Как быть?»

Почему возникает ошибка: «React refers to a UMD global, but the current file is a module»?

Ошибка появляется, когда TypeScript не может однозначно определить, как обрабатывать импорт React. Вот типичный сценарий:

// App.tsx
import React from 'react';
import { useState } from 'react';

const App: React.FC = () => {
    const [count, setCount] = useState(0);
    return <div>{count}</div>;
};

export default App;

Вы запускаете компиляцию, и TypeScript выдаёт ошибку: 'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.

Почему? Потому что в @types/react есть такое объявление (упрощённо):

// в файле index.d.ts из @types/react
export = React;
export as namespace React;

declare namespace React {
    // ...типы
}

Ключевая строка — export as namespace React. Она говорит TypeScript: «Этот модуль также доступен как глобальная переменная React (UMD)». Когда ваш файл является модулем (содержит export), TypeScript может не понять, хотите ли вы использовать глобальный React или импортированный. В результате — конфликт.

Как исправить: три проверенных способа

Способ 1: Явный импорт (самый распространённый)

Самый простой способ — убедиться, что вы явно импортируете React, даже если используете JSX. В современных версиях React (начиная с 17) JSX трансформируется автоматически, и импорт React не обязателен. Но если вы используете старую версию или настройки, добавьте:

import React from 'react';

Если ошибка остаётся, проверьте, что tsconfig.json настроен правильно:

{
    "compilerOptions": {
        "jsx": "react-jsx", // или "react" для старых версий
        "moduleResolution": "node",
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true
    }
}

Параметр esModuleInterop включает совместимость между CommonJS и ESM, что часто решает проблему.

Способ 2: Отключение UMD-глобала в tsconfig

Вы можете явно запретить TypeScript использовать UMD-глобалы. Добавьте в tsconfig.json:

{
    "compilerOptions": {
        ""types": ["react"] // только если хотите отключить глобалы
    }
}

Или более жёсткий вариант — установить "skipLibCheck": true, но это отключит проверку всех типов в библиотеках, что не рекомендуется.

Способ 3: Использовать import * as React

Иногда помогает замена импорта на звёздочный:

import * as React from 'react';

Это явно указывает TypeScript, что вы работаете с модулем, а не с глобалом. Однако этот способ может нарушить tree-shaking в некоторых сборщиках, так что используйте его с осторожностью.

Как это работает под капотом: разбор деклараций TypeScript

Давайте заглянем глубже. Когда вы пишете import React from 'react', TypeScript ищет файл деклараций для пакета react. В @types/react есть два ключевых объявления:

  • export = React — экспорт для CommonJS/ESM.
  • export as namespace React — объявление UMD-глобала.

Когда TypeScript видит export as namespace, он добавляет React в глобальное пространство имён. В модульном файле это вызывает двусмысленность: компилятор не знает, ссылаетесь ли вы на глобал или на импорт. Отсюда и ошибка.

Решение TypeScript — предложить добавить импорт. Но если импорт уже есть, проблема может быть в порядке разрешения модулей. Например, если ваш файл находится в папке, где TypeScript не видит node_modules из-за неправильного rootDir.

Ещё один интересный момент: ошибка часто возникает в файлах с расширением .tsx, где используется JSX. JSX-трансформация требует, чтобы React был в области видимости. Если TypeScript не может определить, отку

Блоги

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