Avatar ·

Как обратиться к глобальной переменной внутри модуля в TypeScript?

Всем привет! Я новичок в TypeScript и столкнулся с проблемой при переходе от обычного JavaScript к модульной системе. У меня есть проект, где я использую глобальную переменную `window.myApp`, объявленную в отдельном скрипте (например, в `config.js`), который подключается до моего основного модуля: ```typescript // config.js (подключается до модулей) window.myApp = { apiBaseUrl: 'https://api.example.com', debugMode: true }; ``` В моём TypeScript-файле я пытаюсь получить доступ к этой глобальной переменной, но TypeScript выдаёт ошибку: ```typescript // main.ts import { fetchData } from './api'; const config = window.myApp; // Ошибка: Property 'myApp' does not exist on type 'Window' console.log(config.apiBaseUrl); ``` Я понимаю, что TypeScript строго типизирован и не знает о существовании `myApp` на объекте `window`. Как правильно объявить и использовать глобальные переменные в TypeScript-модулях? Я пробовал использовать `declare var window.myApp`, но это не сработало. Нужно ли мне создавать отдельный файл деклараций или есть способ проще? Буду благодарен за примеры с кодом и объяснение, как это работает в контексте модулей. <<>>

Проблема: TypeScript не знает о глобальных переменных

Когда вы работаете с модулями (файлы с import/export), TypeScript изолирует код. Глобальные переменные, объявленные вне модуля, не видны автоматически — нужно явно сообщить TypeScript об их существовании.

Ошибка Property 'myApp' does not exist on type 'Window' возникает, потому что стандартный тип Window не содержит свойства myApp. Решение — расширить интерфейс Window через объявление (declaration).

Решение №1: Расширение интерфейса Window

Создайте файл global.d.ts (или добавьте в существующий файл деклараций) и расширьте интерфейс:

// global.d.ts
interface Window {
  myApp: {
    apiBaseUrl: string;
    debugMode: boolean;
    // Добавьте другие поля по мере необходимости
  };
}

Теперь в любом модуле вы можете писать:

// main.ts
const config = window.myApp; // ✅ Ошибки нет
console.log(config.apiBaseUrl); // 'https://api.example.com'

Решение №2: Использование declare global

Если вы хотите объявить прямо в модуле, используйте конструкцию declare global:

// main.ts
import { fetchData } from './api';

declare global {
  interface Window {
    myApp: {
      apiBaseUrl: string;
      debugMode: boolean;
    };
  }
}

const config = window.myApp;
console.log(config.apiBaseUrl);

Этот способ удобен, когда глобальная переменная используется только в одном файле. Для многократного использования лучше вынести в .d.ts.

Важные моменты:

  • Глобальные переменные должны существовать во время выполнения — они объявлены в config.js, который загружается до модуля.
  • Не злоупотребляйте глобальными переменными — в модульной системе лучше передавать конфигурацию через импорт или DI (внедрение зависимостей).
  • Для сложных объектов опишите полный интерфейс, чтобы TypeScript проверял типы полей.

Пример полной настройки:

// types/global.d.ts
interface AppConfig {
  apiBaseUrl: string;
  debugMode: boolean;
  version: string;
}

interface Window {
  myApp: AppConfig;
}

// main.ts
const config: AppConfig = window.myApp;
// Теперь TypeScript знает все поля config

Альтернативный подход: избегать глобальных переменных

Лучшая практика — передавать конфигурацию через модули:

// config.ts
export const appConfig = {
  apiBaseUrl: 'https://api.example.com',
  debugMode: true
};

// main.ts
import { appConfig } from './config';
console.log(appConfig.apiBaseUrl); // ✅ Чисто, типобезопасно

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

<<>>

Дополнительный подход: Использование declare var

Если вы не хотите расширять интерфейс Window, можно объявить глобальную переменную напрямую с помощью declare var или declare const:

// main.ts
declare const myApp: {
  apiBaseUrl: string;
  debugMode: boolean;
};

// Использование:
console.log(myApp.apiBaseUrl); // ✅ Работает

Этот метод создаёт глобальную переменную myApp в области видимости модуля, но не привязывает её к window. Если ваша переменная действительно находится на window, такой подход может привести к путанице — TypeScript будет считать, что переменная существует сама по себе, хотя на самом деле она доступна через window.myApp.

Когда использовать: Если глобальная переменная объявлена не на window, а через var в глобальной области видимости (например, в скрипте без модулей). Но в современных проектах это редкость — обычно всё привязано к window.

Совет: Используйте модули

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

// config.ts
export const API_CONFIG = {
  baseUrl: 'https://api.example.com',
  debug: true
};

// main.ts
import { API_CONFIG } from './config';
// Теперь никаких глобальных переменных!