Avatar ·

Как правильно импортировать JSON файл в TypeScript? Ошибка "Cannot find module"

Всем привет! Я начал изучать TypeScript и столкнулся с проблемой при попытке импортировать JSON файл. У меня есть конфигурационный файл `config.json`: ```json { "apiUrl": "https://api.example.com", "port": 3000, "debug": true } ``` И я пытаюсь импортировать его в своём TypeScript файле `app.ts`: ```typescript import config from './config.json'; console.log(config.apiUrl); ``` Но получаю ошибку от компилятора: > "Cannot find module './config.json'. Consider using '--resolveJsonModule' to import module with '.json' extension." Я использую TypeScript 4.9.5. Пробовал добавить `"resolveJsonModule": true` в `tsconfig.json`, но это не помогло. Может быть, я что-то делаю не так? Как правильно импортировать JSON файлы в TypeScript? Нужно ли устанавливать какие-то дополнительные пакеты или настройки? Буду благодарен за подробное объяснение с примерами. Важно, чтобы код работал и в Node.js, и в браузере. <<>>

Решение проблемы с импортом JSON в TypeScript

Проблема, с которой вы столкнулись, типична для начинающих разработчиков. TypeScript по умолчанию не умеет импортировать JSON-файлы, потому что это нестандартное поведение для JavaScript. Однако современные версии TypeScript поддерживают эту возможность через специальные настройки компилятора.

Вот пошаговое решение вашей проблемы:

Шаг 1: Настройка tsconfig.json

Убедитесь, что в вашем tsconfig.json включены следующие опции:

{
  "compilerOptions": {
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "moduleResolution": "node",
    "target": "ES2020",
    "module": "commonjs"
  }
}
  • resolveJsonModule — разрешает импорт .json файлов как модулей
  • esModuleInterop — позволяет использовать синтаксис ES-модулей с CommonJS
  • moduleResolution: "node" — использует Node.js алгоритм поиска модулей

Шаг 2: Правильный импорт

После настройки вы можете импортировать JSON несколькими способами:

// Вариант 1: Импорт всего объекта (рекомендуемый)
import config from './config.json';
console.log(config.apiUrl); // "https://api.example.com"

// Вариант 2: Импорт с явным указанием типа
import * as config from './config.json';
console.log(config.default.port); // 3000

// Вариант 3: Импорт конкретных полей
import { apiUrl, port } from './config.json';
console.log(apiUrl, port);

Шаг 3: Типизация импортируемого JSON (опционально)

Для лучшей типизации можно создать декларацию модуля:

// config.d.ts
declare module "*.json" {
  const value: any;
  export default value;
}

// Или более строгий вариант:
declare module "*.json" {
  interface Config {
    apiUrl: string;
    port: number;
    debug: boolean;
  }
  const config: Config;
  export default config;
}

Шаг 4: Для Node.js с CommonJS

Если вы используете CommonJS модули (старый стиль Node.js), можно использовать require:

const config = require('./config.json');
console.log(config.apiUrl);

Шаг 5: Для браузера (Webpack, Vite, etc.)

В современных сборщиках (Webpack 5+, Vite) JSON импортируется "из коробки". Дополнительных настроек не требуется.

Проверка работоспособности

После всех настроек перезапустите компилятор TypeScript (или редактор кода). Если ошибка остаётся — проверьте:

  • Находится ли tsconfig.json в корне проекта
  • Не переопределены ли настройки в других конфигурационных файлах (например, tsconfig.node.json)
  • Правильно ли указан путь к JSON файлу (относительно текущего файла)

Для полной уверенности можно скомпилировать файл вручную: tsc app.ts — ошибок быть не должно.

<<>>

Альтернативный подход: чтение JSON через fs в Node.js

Если по каким-то причинам вы не можете использовать resolveJsonModule (например, работаете с устаревшей версией TypeScript или нужна динамическая загрузка), можно читать JSON файлы через fs модуль Node.js:

import * as fs from 'fs';
import * as path from 'path';

function loadConfig(): any {
  const filePath = path.join(__dirname, 'config.json');
  const rawData = fs.readFileSync(filePath, 'utf-8');
  return JSON.parse(rawData);
}

const config = loadConfig();
console.log(config.apiUrl);

Этот метод даёт больше контроля: вы можете обрабатывать ошибки, проверять существование файла, кэшировать данные. Минус — асинхронность приходится обрабатывать вручную и теряется статическая типизация (хотя её можно добавить через дженерики):

interface Config {
  apiUrl: string;
  port: number;
  debug: boolean;
}

function loadConfig<T>(filePath: string): T {
  const rawData = fs.readFileSync(filePath, 'utf-8');
  return JSON.parse(rawData) as T;
}

const config = loadConfig<Config>('config.json');

Этот подход особенно полезен, когда JSON-файл генерируется динамически или его путь определяется во время выполнения программы.