Не удалось найти файл объявления модуля

Обновлено: 04.07.2024

В этом разделе предполагается наличие некоторых базовых знаний о модулях. Дополнительную информацию см. в документации по модулям.

Разрешение модуля — это процесс, который компилятор использует для определения того, на что ссылается импорт. Рассмотрим оператор импорта, например import < a >from "moduleA" ; чтобы проверить любое использование a , компилятор должен точно знать, что он представляет, и ему нужно будет проверить его модуль определения A .

В этот момент компилятор спросит: "Какова форма модуля A?" Хотя это звучит просто, модуль A можно определить в одном из ваших собственных файлов .ts/.tsx или в .d.ts, от которого зависит ваш код.

Сначала компилятор попытается найти файл, представляющий импортированный модуль. Для этого компилятор следует одной из двух разных стратегий: Classic или Node. Эти стратегии сообщают компилятору где искать модуль A .

Если это не сработало и если имя модуля не является относительным (а в случае "moduleA" это так), то компилятор попытается найти объявление внешнего модуля. Далее мы рассмотрим неотносительный импорт.

Наконец, если компилятору не удалось разрешить модуль, он зарегистрирует ошибку. В этом случае ошибка будет выглядеть примерно так: ошибка TS2307: не удается найти модуль 'moduleA'.

Относительный и не относительный импорт модулей

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

Относительный импорт начинается с / , ./ или ../ . Вот некоторые примеры:

  • импортировать запись из "./components/Entry";
  • импорт < DefaultHeaders >из "../constants/http";
  • импортировать "/mod";

Любой другой импорт считается не относительным. Вот некоторые примеры:

  • импортировать * как $ из "jquery";
  • импорт <компонента>из "@angular/core";

Относительный импорт разрешается относительно импортируемого файла и не может разрешаться в объявление внешнего модуля. Вы должны использовать относительный импорт для своих собственных модулей, которые гарантированно сохранят свое относительное местоположение во время выполнения.

Неотносительный импорт может быть разрешен относительно baseUrl или с помощью сопоставления путей, о чем мы расскажем ниже. Они также могут разрешаться в объявления внешних модулей. Используйте неотносительные пути при импорте любых внешних зависимостей.

Стратегии разрешения модулей

Существует две возможные стратегии разрешения модулей: Node и Classic. Вы можете использовать параметр moduleResolution, чтобы указать стратегию разрешения модуля. Если не указано, по умолчанию используется Node для --module commonjs и Classic в противном случае (включая случаи, когда для модуля установлено значение amd , system , umd , es2015 , esnext и т. д.).

Примечание. Разрешение модуля узла чаще всего используется в сообществе TypeScript и рекомендуется для большинства проектов. Если у вас возникли проблемы с разрешением импорта и экспорта в TypeScript, попробуйте установить moduleResolution: "node", чтобы посмотреть, решит ли это проблему.

Раньше это была стратегия разрешения TypeScript по умолчанию. В настоящее время эта стратегия в основном используется для обеспечения обратной совместимости.

Относительный импорт будет разрешен относительно импортируемого файла. Таким образом, импорт < b >из "./moduleB" в исходный файл /root/src/folder/A.ts приведет к следующим поискам:

  1. /root/src/folder/moduleB.ts
  2. /root/src/folder/moduleB.d.ts

Однако для неотносительного импорта модулей компилятор просматривает дерево каталогов, начиная с каталога, содержащего файл импорта, пытаясь найти соответствующий файл определения.

Неотносительный импорт в moduleB, такой как импорт из "moduleB" в исходном файле /root/src/folder/A.ts , приведет к попытке найти "moduleB" в следующих местах:< /p>

  1. /root/src/folder/moduleB.ts
  2. /root/src/folder/moduleB.d.ts
  3. /root/src/moduleB.ts
  4. /root/src/moduleB.d.ts
  5. /root/moduleB.ts
  6. /root/moduleB.d.ts
  7. /moduleB.ts
  8. /moduleB.d.ts

Эта стратегия разрешения пытается имитировать механизм разрешения модулей Node.js во время выполнения. Полный алгоритм разрешения Node.js описан в документации модуля Node.js.

Как Node.js разрешает модули

Чтобы понять, какие шаги будет выполнять компилятор TS, важно пролить свет на модули Node.js. Традиционно импорт в Node.js выполняется путем вызова функции с именем require . Поведение Node.js будет различаться в зависимости от того, задан ли require относительный или неотносительный путь.

Относительные пути довольно просты. В качестве примера рассмотрим файл, расположенный по адресу /root/src/moduleA.js, который содержит import var x = require("./moduleB"); Node.js разрешает этот импорт в следующем порядке:

Запросите файл с именем /root/src/moduleB.js , если он существует.

Спросите папку /root/src/moduleB, содержит ли она файл с именем package.json, в котором указан «основной» модуль. В нашем примере, если Node.js обнаружил файл /root/src/moduleB/package.json, содержащий < "main": "lib/mainModule.js" >, то Node.js будет ссылаться на /root/src/moduleB/ lib/mainModule.js .

Спросите папку /root/src/moduleB, содержит ли она файл с именем index.js . Этот файл неявно считается «основным» модулем этой папки.

Подробнее об этом можно прочитать в документации Node.js по файловым модулям и модулям папок.

Однако разрешение неродственного имени модуля выполняется иначе. Node будет искать ваши модули в специальных папках с именами node_modules. Папка node_modules может находиться на том же уровне, что и текущий файл, или выше в цепочке каталогов. Node просматривает цепочку каталогов, просматривая каждый node_modules, пока не найдет модуль, который вы пытались загрузить.

Вслед за нашим примером выше, рассмотрим, если /root/src/moduleA.js вместо этого использовал не относительный путь и имел import var x = require("moduleB"); . После этого Node попытается преобразовать moduleB в каждое из местоположений, пока одно из них не сработает.

  1. /root/src/node_modules/moduleB.js
  2. /root/src/node_modules/moduleB/package.json (если указано основное свойство)
  3. /root/src/node_modules/moduleB/index.js

Обратите внимание, что Node.js перешел вверх по каталогу на шагах (4) и (7).

Подробнее об этом процессе можно прочитать в документации Node.js по загрузке модулей из node_modules .

Как TypeScript разрешает модули

TypeScript будет имитировать стратегию разрешения времени выполнения Node.js, чтобы найти файлы определений для модулей во время компиляции. Для этого TypeScript накладывает расширения исходного файла TypeScript (.ts, .tsx и .d.ts) на логику разрешения Node. TypeScript также будет использовать поле именованных типов в package.json, чтобы отразить назначение «основного» — компилятор будет использовать его, чтобы найти «основной» файл определения для консультации.

Например, оператор импорта, такой как import < b >from "./moduleB" в /root/src/moduleA.ts, приведет к попытке найти "./moduleB" в следующих местах:

  1. /root/src/moduleB.ts
  2. /root/src/moduleB.tsx
  3. /root/src/moduleB.d.ts
  4. /root/src/moduleB/package.json (если указано свойство типов)
  5. /root/src/moduleB/index.ts
  6. /root/src/moduleB/index.tsx
  7. /root/src/moduleB/index.d.ts

Вспомните, что Node.js искал файл с именем moduleB.js , затем соответствующий package.json , а затем index.js .

Аналогичным образом неотносительный импорт будет следовать логике разрешения Node.js, сначала ища файл, а затем ища подходящую папку. Таким образом, импорт из "moduleB" в исходном файле /root/src/moduleA.ts приведет к следующему поиску:

  1. /root/src/node_modules/moduleB.ts
  2. /root/src/node_modules/moduleB.tsx
  3. /root/src/node_modules/moduleB.d.ts
  4. /root/src/node_modules/moduleB/package.json (если указано свойство типов)
  5. /root/src/node_modules/@types/moduleB.d.ts
  6. /root/src/node_modules/moduleB/index.ts
  7. /root/src/node_modules/moduleB/index.tsx
  8. /root/src/node_modules/moduleB/index.d.ts

Не пугайтесь количества шагов здесь — TypeScript по-прежнему только дважды перескакивает вверх по каталогам на шагах (9) и (17). На самом деле это не сложнее, чем то, что делает сам Node.js.

Флаги разрешения дополнительных модулей

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

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

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

Использование baseUrl является обычной практикой в ​​приложениях, использующих загрузчики модулей AMD, где модули «разворачиваются» в одну папку во время выполнения. Исходники этих модулей могут находиться в разных каталогах, но скрипт сборки соберет их все вместе.

Установка baseUrl сообщает компилятору, где искать модули. Предполагается, что все импорты модулей с не относительными именами относятся к baseUrl .

Значение baseUrl определяется как:

  • значение аргумента командной строки baseUrl (если задан относительный путь, он вычисляется на основе текущего каталога)
  • значение свойства baseUrl в файле tsconfig.json (если задан относительный путь, он вычисляется на основе расположения файла tsconfig.json)

Обратите внимание, что установка baseUrl не влияет на относительный импорт модулей, поскольку они всегда разрешаются относительно импортируемых файлов.

Дополнительную документацию по baseUrl можно найти в документации по RequireJS и SystemJS.

Иногда модули не находятся непосредственно под baseUrl. Например, импорт модуля «jquery» будет преобразован во время выполнения в «node_modules/jquery/dist/jquery.slim.min.js». Загрузчики используют конфигурацию сопоставления для сопоставления имен модулей с файлами во время выполнения, см. документацию по RequireJs и документацию по SystemJS.

Компилятор TypeScript поддерживает объявление таких сопоставлений с помощью свойства paths в файлах tsconfig.json. Вот пример того, как указать свойство paths для jquery.

Обратите внимание, что пути разрешаются относительно baseUrl . При установке для baseUrl значения, отличного от "." , то есть каталог tsconfig.json , сопоставления должны быть изменены соответствующим образом. Скажем, вы установили "baseUrl": "./src" в приведенном выше примере, тогда jquery должен быть сопоставлен с "../node_modules/jquery/dist/jquery" .

Использование путей также позволяет выполнять более сложные сопоставления, включая несколько запасных местоположений. Рассмотрим конфигурацию проекта, в которой только некоторые модули доступны в одном месте, а остальные — в другом. Шаг сборки объединит их все в одном месте. Макет проекта может выглядеть так:

Соответствующий tsconfig.json будет выглядеть так:

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

  1. "*": означает то же имя без изменений, поэтому map =>/
  2. "generated/*" означает имя модуля с добавленным префиксом "generated", поэтому map =>/generated/

Следуя этой логике, компилятор попытается разрешить два импорта как таковые:

  1. шаблон '*' совпадает, и подстановочный знак захватывает полное имя модуля
  2. попробуйте первую замену в списке: '*' -> folder1/file2
  3. результатом замены является неотносительное имя — объедините его с baseUrl -> projectRoot/folder1/file2.ts .
  4. Файл существует. Готово.
  1. шаблон '*' совпадает, и подстановочный знак захватывает полное имя модуля
  2. попробуйте первую замену в списке: '*' -> folder2/file3
  3. результатом замены является неотносительное имя — объедините его с baseUrl -> projectRoot/folder2/file3.ts .
  4. Файл не существует, перейти ко второй замене
  5. вторая замена ‘сгенерировано/*’ -> сгенерировано/папка2/файл3
  6. результатом замены является неотносительное имя — объедините его с baseUrl -> projectRoot/generated/folder2/file3.ts .
  7. Файл существует. Готово.

Виртуальные каталоги с корневыми каталогами

Иногда исходники проекта из нескольких каталогов во время компиляции объединяются для создания одного выходного каталога. Это можно рассматривать как набор исходных каталогов, создающих «виртуальный» каталог.

Используя rootDirs , вы можете сообщить компилятору корни, составляющие этот «виртуальный» каталог; и, таким образом, компилятор может разрешить импорт относительных модулей в эти «виртуальные» каталоги, как если бы они были объединены в один каталог.

Файлы в src/views – это пользовательский код для некоторых элементов управления пользовательского интерфейса. Файлы в generate/templates представляют собой код привязки шаблона пользовательского интерфейса, автоматически сгенерированный генератором шаблонов как часть сборки. Шаг сборки скопирует файлы из /src/views и /generated/templates/views в один и тот же каталог в выходных данных. Во время выполнения представление может ожидать, что его шаблон будет существовать рядом с ним, поэтому его следует импортировать, используя относительное имя, например "./template" .

Чтобы указать это отношение к компилятору, используйте rootDirs . rootDirs задают список корневых, содержимое которых должно объединяться во время выполнения. Итак, следуя нашему примеру, файл tsconfig.json должен выглядеть так:

Каждый раз, когда компилятор видит импорт относительного модуля в подпапке одного из корневых каталогов, он пытается найти этот импорт в каждой из записей корневых каталогов.

Гибкость rootDirs не ограничивается указанием списка физических исходных каталогов, которые логически объединены. Предоставленный массив может включать любое количество случайных, произвольных имен каталогов, независимо от того, существуют они или нет. Это позволяет компилятору захватывать сложные функции связывания и времени выполнения, такие как условное включение и подключаемые модули загрузчика проекта, безопасным для типов способом.

Предположим, что каждый из этих модулей экспортирует массив строк. Например ./zh/messages может содержать:

Разрешение модуля трассировки

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

Допустим, у нас есть пример приложения, в котором используется модуль машинописного текста. app.ts имеет такой импорт, как import * as ts from "typescript" .

Вызов компилятора с помощью traceResolution

Результаты в выводе, например:

На что обратить внимание

======== Модуль разрешения ‘typescript’ из ‘src/app.ts’. ========

Разрешение модуля не указано, используется NodeJs.

'package.json' имеет поле 'types' './lib/typescript.d.ts', которое ссылается на 'node_modules/typescript/lib/typescript.d.ts'.

======== Имя модуля «typescript» было успешно преобразовано в «node_modules/typescript/lib/typescript.d.ts». ========

Обычно компилятор пытается разрешить импорт всех модулей перед началом процесса компиляции. Каждый раз, когда он успешно разрешает импорт в файл, этот файл добавляется в набор файлов, которые компилятор будет обрабатывать позже.

Параметры компилятора noResolve предписывают компилятору не «добавлять» в компиляцию файлы, которые не были переданы в командной строке. Он по-прежнему будет пытаться преобразовать модуль в файлы, но если файл не указан, он не будет включен.

Компиляция app.ts с использованием noResolve должна привести к следующему:

  • Правильный поиск модуля A в том виде, в каком он был передан в командной строке.
  • Ошибка: не удалось найти модуль B, так как он не был передан.

Почему модуль в списке исключений по-прежнему подхватывается компилятором?

tsconfig.json превращает папку в «проект». Без указания каких-либо записей «исключить» или «файлы» все файлы в папке, содержащей tsconfig.json, и все его подкаталоги будут включены в вашу компиляцию. Если вы хотите исключить некоторые файлы, используйте «exclude», если вы предпочитаете указывать все файлы вместо того, чтобы позволить компилятору искать их, используйте «files».

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

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

Документация TypeScript — это проект с открытым исходным кодом. Помогите нам улучшить эти страницы, отправив запрос на слияние ❤

Мне больше всего нравится в TypeScript постепенный набор текста. Мне не нужно доказывать компилятору, что я могу отказаться. Но иногда отказаться сложнее, чем в других случаях.

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

Когда я импортирую модуль JS, не созданный для TS, мне мешает компилятор. Там написано что-то вроде:

Как обойти эту ошибку?

Вот восемь исправлений, от худшего к лучшему:

TypeScript превратит ваш код в JavaScript даже при наличии ошибок компиляции.

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

Предостережение: параметр компилятора --noEmitOnError заставляет TypeScript отказываться от генерации JavaScript при обнаружении ошибок компиляции. Запустите tsc --noEmitOnError false, чтобы обойти это.

Предостережение: тесты могут блокироваться из-за ошибки. Это происходит со мной, потому что мой тест использует mocha, и мы запускаем mocha с компиляцией TypeScript на лету (наш тестовый скрипт npm запускает mocha --require espower-typescript/guess "test/**/*.test.ts" ) . Иногда mocha вылетает из-за этой ошибки, ничего не выводит и не возвращает ошибку, так что моя сборка выглядит успешной. 😡 Чтобы обойти это: скомпилируйте тест (допустив его сбой), затем запустите mocha на выходе JavaScript, например: $(npm bin)/mocha myParticularTest.test.js

В tsconfig.json в параметрах компилятора установите "noImplicitAny": false . Это заставит его замолчать.

Но тогда вы не получите ошибку, если забудете объявить тип параметра функции. Это плохо!

Внимание: случайное написание кода, похожего на functionsolveAThing(importantParameter) <. > назначит тип any важному параметру.Тогда у вас не будет проверки типа, и он не будет включен в рефакторинг своего типа. Это сжигало нас раньше. 🔥

Это на самом деле мой любимый, но мои коллеги не одобряют.

Создайте файл в любом месте среди ваших файлов .ts. Вставьте в него:

Вот и все, время вечеринки! Все модули, не типизированные иным образом, явно объявляются как any .

Некоторым людям нравится называть этот файл types.d.ts .

Иногда мне нравится называть его allowJavaScriptModules.ts . Это описывает его цель. Не похоже, чтобы этот файл содержал полезные типы.

Вы можете создать файл .d.ts напрямую или создать файл .ts и позволить компилятору вывести .d.ts для вас.

Осторожно: если вы создаете файл .d.ts, вы должны научить .gitignore заботиться о нем. Вы, вероятно, исключили вывод компилятора (включая .d.ts ) из git. Добавьте строку в конец .gitignore с "!" для «не игнорировать это», за которым следует ваше имя файла:

Создайте файл где-нибудь среди исходников TypeScript. Назовите его types.d.ts (или как-то так, см. выше) и вставьте в него:

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

Это делает явное объявление этого модуля как типа any . Это называется «окружающей декларацией», потому что она плавает в глобальном пространстве среди исходных файлов, которые читает компилятор.

Если вам нужны типы, но их никто не создал, то вы создаете то, что вам нужно. Это непросто, но вы получите желаемую безопасность типов.

Если модуль экспортирует только одну вещь (например, функцию или класс), добавьте строку внизу, чтобы указать одну экспортируемую вещь:

Примечание: мне потребовалось некоторое время, чтобы понять это. Я пытался использовать параметры компилятора, такие как --types и --typeRoots, но они ничего не делали. Это проще. Только не забудьте заключить имя модуля в кавычки; иначе объявление не будет найдено.

Пока вы делаете шрифты для пакета, почему бы не сделать их полными? Затем вы можете отправить PR в DefinitelyTyped, и каждый сможет им воспользоваться!

Идеальное решение — прямо в сообщении об ошибке TS7016: npm install @types/ваш-интересующий-пакет .

Это происходит из специального имени пользователя NPM, @types , где люди публикуют объявления TypeScript отдельно от объявляемых ими пакетов.

Внимание: вводя объявления типов, вы можете сделать это двумя способами. Установка npm по умолчанию поместит их в зависимости вашего проекта. Не идеально; эти типы используются во время компиляции, а не во время выполнения. Обычно зависимости времени сборки добавляются с помощью npm install --save-dev , и они записываются в devDependencies . Они не поставляются с вашим производственным кодом и не добавляются к транзитивным зависимостям.

Внимание: если ваш проект представляет собой библиотеку, то людям, использующим вашу библиотеку, потребуются эти типы. Если вы поместите их в devDependencies , ваши последующие пользователи не получат их, поэтому они получат ошибки компиляции. Когда вы создаете библиотеку, поместите эти типы в зависимости (по умолчанию). Не используйте --save-dev для установки пакетов из @types при публикации библиотеки TypeScript.

Выводы

Восемь! Это множество способов решить одну проблему.

Это гибкость поэтапного ввода TypeScript. Вы можете начать с грубых обходных путей и надеяться, что кто-то другой решит сложные проблемы (путем публикации типов). Или вы можете внести свой вклад сами! Или можно жить без типов, для одного модуля или для всех. Все эти возможности открыты для вас. Выберите, насколько компилятор вызовет у вас затруднения.

И помните: всегда читайте сообщение об ошибке.

Джессика Керр
< /p>

Джессика Керр

Симматолог, разработчик, спикер, мать, сумасшедший. Атомист. Обучение и рост. она/ее

Начните использовать Atomist уже сегодня. Получите ранний доступ.

Контейнеризация проекта Clojure

Наша команда использовала Dockerfiles в течение нескольких лет, но недавно обнаружила, что мы можем получить лучшие результаты, используя только Jib. В этом посте мы покажем вам, как это сделать и где вы увидите наиболее важные результаты.

Контейнеризация проекта Clojure

Наша команда использовала Dockerfiles в течение нескольких лет, но недавно обнаружила, что мы можем получить лучшие результаты, используя только Jib. В этом посте мы покажем вам, как это сделать и где вы увидите наиболее важные результаты.

Подготовка к следующему log4shell

Мы не можем предсказать, где будет следующая уязвимость (или, точнее, где она уже есть). Вместо этого мы должны подготовиться к тому, чего еще не знаем.

Подготовка к следующему log4shell

Мы не можем предсказать, где будет следующая уязвимость (или, точнее, где она уже есть). Вместо этого мы должны подготовиться к тому, чего еще не знаем.

Почему вы, вероятно, игнорируете уязвимости контейнера

Узнавайте, где именно и как уязвимости оказываются в ваших образах контейнеров, чтобы вы могли исправить те из них, которые имеют значение, и перестать игнорировать уязвимости.

Почему вы, вероятно, игнорируете уязвимости контейнера

Узнавайте, где именно и как уязвимости оказываются в ваших образах контейнеров, чтобы вы могли исправить те из них, которые имеют значение, и перестать игнорировать уязвимости.

Я прочитал, как работает разрешение модуля TypeScript.

У меня есть следующий репозиторий: @ts-stack/di. После компиляции структура каталогов выглядит следующим образом:

В моем package.json я написал "main": "dist/index.js" .

В Node.js все работает нормально, но TypeScript:

Не удалось найти файл объявления для модуля '@ts-stack/di'. '/path/to/node_modules/@ts-stack/di/dist/index.js' неявно имеет тип "любой".

И еще, если я импортирую следующим образом, то все работает:

Что я делаю не так?

31 Ответ 31

Вот два других решения

Если модуль не ваш - попробуйте установить типы из @types :

Если при установке возникают указанные выше ошибки, попробуйте изменить операторы импорта на require :

Если вы не можете найти имя, запустите это для TypeScript 2.0: npm install @types/node --save-dev

Я использую реактивный машинописный проект с YARN, требуется только работа. Спасибо. const yourModuleName = require('module-name');

@DanielKmak У меня тот же вопрос. Похоже, просто использование require вместо этого работает. Но к вашему сведению: существует репозиторий под названием DefinitelyTyped (упомянутый в другом ответе ниже), который может предоставлять типы, если то, что вы импортируете, достаточно популярно.

Если вы импортируете сторонний модуль foo, который не предоставляет типизации ни в самой библиотеке, ни в пакете @types/foo (созданный из репозитория DefinitelyTyped), вы можете сделать эту ошибку можно устранить, объявив модуль в файле с расширением .d.ts. TypeScript ищет файлы .d.ts в тех же местах, что и обычные файлы .ts: как указано в разделе «файлы», «включать» и «исключать» в tsconfig.json .

Затем, когда вы импортируете foo, он будет просто напечатан как any .

В качестве альтернативы, если вы хотите свернуть свои собственные наборы текста, вы также можете сделать это:

Тогда это скомпилируется правильно:

Вам не нужно предоставлять полные типизации для модуля, достаточно только тех битов, которые вы фактически используете (и для которых нужны правильные типизации), поэтому это особенно легко сделать, если вы используете довольно небольшое количество API.

С другой стороны, если вы не заботитесь о типах внешних библиотек и хотите, чтобы все библиотеки без типов были импортированы как любые , вы можете добавить это в файл с расширением .d.ts:

Преимущество (и недостаток) этого заключается в том, что вы можете импортировать абсолютно все, что угодно, и TS скомпилируется.

@Tom Он ищет файлы .d.ts в тех же местах, что и обычные файлы .ts: как указано «files», «include» и «exclude» в tsconfig.json . Я бы не рекомендовал использовать для этой цели typeRoots: он предназначен для расположения модулей внешних типов (т. е. node_modules/@types ), а не отдельных файлов .d.ts.

Для того, чтобы это работало, мне пришлось объявить модуль '. ' первая строка кода в файле module.d.ts и включает все импорты внутри блока модуля, а не перед ним. До того, как я это сделал, компилятор говорил, что не может найти модуль.

Будет ли объявление модуля '*' гарантировать, что компилируются только пакеты без типизации, или он будет мешать пакетам, которые вообще имеют типизацию?

Если вы получаете такую ​​ошибку при использовании ts-node , ознакомьтесь с документацией по ts-node Help! Мои типы отсутствуют!. Я потратил несколько часов, пытаясь выяснить, почему компилятор не видит мой .d.ts .

Если вам нужно быстрое исправление, просто добавьте это перед строкой импорта:

Это вызывает ошибку в более поздних версиях eslint: error Не используйте комментарии "// @ts-ignore", поскольку они подавляют ошибки компиляции @typescript-eslint/ban-ts-ignore

@Hykilpikonna Я считаю, что вы можете добавить / * eslint-disable */, чтобы отключить eslint перед использованием // @ts-ignore, а затем добавить /* eslint-enable */ после проблемной строки кода, чтобы снова включить eslint для остальной части вашего файла.

Для ситуации, когда вы устанавливаете собственный пакет npm

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

Удалить .js из "основного": "dist/index.js" в package.json .

Папка dist — это место, где компилятор TS хранит файлы вашего модуля.

Я немного мучился с этим: если у вас есть собственный пакет, обязательно удалите старое содержимое папки dist вашего пакета (или целых модулей node_modules в вашем проекте) и снова запустите сборщик. Даже после этого редактирования у меня все еще был старый index.js в dist, что вызвало предупреждение для меня.

Спасибо за это - ваш английский был не очень ясен, но это помогло, мой ввод был неправильным. Я внес несколько изменений, чтобы сделать ответ более понятным.

TypeScript в основном реализует правила и добавляет типы в ваш код, чтобы сделать его более понятным и точным из-за отсутствия ограничений в Javascript. TypeScript требует, чтобы вы описали свои данные, чтобы компилятор мог проверить ваш код и найти ошибки. Компилятор сообщит вам, используете ли вы несоответствующие типы, выходите ли вы за рамки или пытаетесь вернуть другой тип. Итак, когда вы используете внешние библиотеки и модули с TypeScript, они должны содержать файлы, описывающие типы в этом коде. Эти файлы называются файлами объявления типов с расширением d.ts. Большинство типов объявлений для модулей npm уже написаны, и вы можете включить их, используя npm install @types/module_name (где module_name — это имя модуля, типы которого вы хотите включить).

Однако существуют модули, у которых нет определений типов, и чтобы устранить ошибку, импортируйте модуль с помощью import * as module_name from 'module-name' , создайте папку typings в корне вашего проект, внутри создайте новую папку с именем вашего модуля и в этой папке создайте файл module_name.d.ts и напишите declare module 'module_name' . После этого просто перейдите в файл tsconfig.json и добавьте «typeRoots»: [ «../../typings», «../../node_modules/@types»] в параметрах компилятора (с правильным относительным путем к ваши папки), чтобы сообщить TypeScript, где он может найти определения типов ваших библиотек и модулей, и добавить новое свойство «исключить»: [»../../node_modules», «../../typings»] для файл. Вот пример того, как должен выглядеть ваш файл tsconfig.json:

При этом ошибка исчезнет, ​​и вы сможете придерживаться последних правил ES6 и TypeScript.

Я прочитал, как работает разрешение модуля TypeScript.

У меня есть следующий репозиторий: @ts-stack/di. После компиляции структура каталогов выглядит следующим образом:

В моем package.json я написал "main": "dist/index.js" .

В Node.js все работает нормально, но TypeScript:

Не удалось найти файл объявления для модуля '@ts-stack/di'. '/path/to/node_modules/@ts-stack/di/dist/index.js' неявно имеет тип "любой".

И еще, если я импортирую следующим образом, то все работает:

Что я делаю не так?

Этот вопрос помечен модулями машинописного текста

~ Вопрос задан 22.12.2016 22:28:24

16 ответов

То чувство, когда два дня высматриваешь и находишь вот так: просто убери .js из "основного": "dist/index.js" в package.json и все нормально работает!

UPD: этот ответ относителен, если у вас есть собственный пакет npm, если нет - см. мой ответ ниже.

И если приведенный выше ответ не решен, импортируйте свой модуль, попробуйте просто добавить типизацию в package.json :

Конечно, здесь папка dist - это место, где хранятся файлы вашего модуля.

~ Отвечено 2016-12-23 20:09:54

Вот два других решения

Если модуль не ваш - попробуйте установить типы из @types :

Если при установке возникают указанные выше ошибки, попробуйте изменить операторы импорта на require :

~ Отвечено 2017-02-28 10:16:08

Если вы импортируете сторонний модуль foo, который не предоставляет типизации ни в самой библиотеке, ни в пакете @types/foo (созданный из репозитория DefinitelyTyped), вы можете сделать эту ошибку можно устранить, объявив модуль в файле с расширением .d.ts. TypeScript ищет файлы .d.ts в тех же местах, что и обычные файлы .ts: как указано в разделе «файлы», «включать» и «исключать» в tsconfig.json .

Затем, когда вы импортируете foo, он будет просто напечатан как any .

В качестве альтернативы, если вы хотите свернуть свои собственные наборы текста, вы также можете сделать это:

Тогда это скомпилируется правильно:

Вам не нужно предоставлять полные типизации для модуля, достаточно только тех битов, которые вы фактически используете (и для которых нужны правильные типизации), поэтому это особенно легко сделать, если вы используете довольно небольшое количество API.

С другой стороны, если вы не заботитесь о типах внешних библиотек и хотите, чтобы все библиотеки без типов были импортированы как любые , вы можете добавить это в файл с расширением .d.ts:

Преимущество (и недостаток) этого заключается в том, что вы можете импортировать абсолютно все, что угодно, и TS скомпилируется.

Если вам нужно быстрое исправление, просто добавьте это перед строкой импорта:

~ Ответ дан 2019-04-08 14:48:34

TypeScript в основном реализует правила и добавляет типы в ваш код, чтобы сделать его более понятным и точным из-за отсутствия ограничений в Javascript. TypeScript требует, чтобы вы описали свои данные, чтобы компилятор мог проверить ваш код и найти ошибки. Компилятор сообщит вам, используете ли вы несоответствующие типы, выходите ли вы за рамки или пытаетесь вернуть другой тип. Итак, когда вы используете внешние библиотеки и модули с TypeScript, они должны содержать файлы, описывающие типы в этом коде.Эти файлы называются файлами объявления типов с расширением d.ts. Большинство типов объявлений для модулей npm уже написаны, и вы можете включить их, используя npm install @types/module_name (где module_name — это имя модуля, типы которого вы хотите включить).

Однако существуют модули, у которых нет определений типов, и чтобы устранить ошибку, импортируйте модуль с помощью import * as module_name from 'module-name' , создайте папку typings в корне вашего проект, внутри создайте новую папку с именем вашего модуля и в этой папке создайте файл module_name.d.ts и напишите declare module 'module_name' . После этого просто перейдите в файл tsconfig.json и добавьте «typeRoots»: [ «../../typings», «../../node_modules/@types»] в параметрах компилятора (с правильным относительным путем к ваши папки), чтобы сообщить TypeScript, где он может найти определения типов ваших библиотек и модулей, и добавить новое свойство «исключить»: [»../../node_modules», «../../typings»] для файл. Вот пример того, как должен выглядеть ваш файл tsconfig.json:

При этом ошибка исчезнет, ​​и вы сможете придерживаться последних правил ES6 и TypeScript.

ЭТО НЕ ПРОБЛЕМА С приложением create-react-app; Типы для @types/react@17.x.x еще не выпущены и требуют решения этой проблемы. WIP можно найти здесь. Я уже создал заметку по этому вопросу в PR.

На самом деле я не знаю, связана ли эта проблема с определениями типов для реакции или сценариев реакции.

При обновлении до TypeScript 4.1.x я получаю следующую ошибку:

Добавление следующего в react-app-env.d.ts решило проблему, но кажется хакерским.

Были бы признательны за любую информацию о том, является ли это проблемой, которую необходимо решить в рамках create-react-app, или чем-то, что необходимо решить с помощью определений типов.

Вот tsconfig.json для справки:

✔️Ответ принят

FWIW, столкнулся с этой проблемой после того, как версия Dependabot поднялась до TypeScript 4.1.3, и для устранения ошибки компиляции было достаточно пряжи add @types/react --dev.

Другие ответы:

Решить с помощью> rm -rf node-modules, rm -rf package-lock.json, yarn install и yarn add @types/react --dev

Поиск этой ошибки приводит к конкретной странице. Итак, я собираюсь разместить здесь то, что сработало для меня, для тех, кто придет позже. Я понимаю, что есть много ссылок, указывающих на то и это. Что касается меня, я просто хочу, чтобы мои ученики начали работать с реакцией, не переходя по десяти различным ссылкам.

Я уверен, что это не "то" решение, а "решение" для тех, кто просто хочет создать простое реагирующее приложение "Hello World" с машинописным текстом. Поисковые системы уже проиндексировали эту страницу как самую популярную по этой ошибке, так что да. разместить его здесь.

[выдержка из моего рабочего дневника разработчика]

Хорошо, попробуем еще раз.

Изменение файлов вручную с .js на .tsx (для файлов с содержимым JSX) и .ts (для файлов, не использующих JSX)

Пожалуйста, установите typescript, запустив npm install typescript. (ошибка)

Теперь я получаю большую ошибку. Не удалось найти файл объявления для модуля «реакция/jsx-runtime». '/node_modules/react/jsx-runtime.js' неявно имеет тип "любой".

Далее ошибка. Не удалось найти файл объявления для модуля «реакция-дом». '/node_modules/react-dom/index.js' неявно имеет тип "любой".

Далее ошибка. Ошибка TypeScript в /src/index.tsx(17,1): ожидалось 1 аргумент, но получено 0.

решение: закомментировать // reportWebVitals(); или на самом деле отправить что-то вроде этого.

Читайте также: