Я читаю, как работает разрешение модуля TypeScript.
У меня есть следующий репозиторий: ts-di. После компиляции структура каталогов выглядит следующим образом:
├── dist
│ ├── annotations.d.ts
│ ├── annotations.js
│ ├── index.d.ts
│ ├── index.js
│ ├── injector.d.ts
│ ├── injector.js
│ ├── profiler.d.ts
│ ├── profiler.js
│ ├── providers.d.ts
│ ├── providers.js
│ ├── util.d.ts
│ └── util.js
├── LICENSE
├── package.json
├── README.md
├── src
│ ├── annotations.ts
│ ├── index.ts
│ ├── injector.ts
│ ├── profiler.ts
│ ├── providers.ts
│ └── util.ts
└── tsconfig.json
В моем пакете.json я написал "main": "dist/index.js"
.
В Node.js все работает отлично, но TypeScript:
import {Injector} from 'ts-di';
Не удалось найти файл декларации для модуля ts-di. '/path/to/node_modules/ts-di/dist/index.js' неявно имеет тип "any".
И все же, если я импортирую как следует, то все работает:
import {Injector} from '/path/to/node_modules/ts-di/dist/index.js';
Что я делаю неправильно?
Это чувство, когда вы смотрите на два дня и находите это так: просто удалите .js
из "main": "dist/index.js"
в package.json
, и все будет хорошо!
"main": "dist/index",
UPD: этот ответ относительный, если у вас есть собственный пакет npm, если нет - см. мой ответ ниже.
И если выше ответ не разрешен импорт вашего модуля, попробуйте просто добавить typings
в package.json
:
"main": "dist/index",
"typings": "dist/index",
Конечно, вот папка dist
- она хранит ваши файлы модулей.
Еще два способа, когда модуль не принадлежит вам - просто попробуйте установить его из @types
:
npm install -D @types/module-name
Или, если ошибка установки - попробуйте переписать import
на require
:
// import * as yourModuleName from 'module-name';
const yourModuleName = require('module-name');
npm install @types/node --save-dev
Если вы импортируете сторонний модуль 'foo'
, который не предоставляет никаких типов, либо в самой библиотеке, либо в пакете @types/foo
(сгенерированном из репозитория DefinitelyTyped), вы можете сделать эту ошибку прочь, объявив модуль в файле .d.ts
:
// foo.d.ts
declare module 'foo';
Затем, когда вы импортируете foo
это будет просто введено как any
.
Кроме того, если вы хотите перевернуть свои собственные тиски, вы также можете это сделать:
// foo.d.ts
declare module 'foo' {
export function getRandomNumber(): number
}
Тогда это скомпилируется правильно:
import { getRandomNumber } from 'foo';
const x = getRandomNumber(); // x is inferred as number
Вам не нужно предоставлять полный набор символов для модуля, достаточно только для битов, которые вы фактически используете (и хотите иметь правильные типизации), поэтому это особенно легко сделать, если вы используете довольно небольшое количество API.
С другой стороны, если вы не заботитесь о типизации внешних библиотек и хотите, чтобы все библиотеки без типизаций были импортированы как any
, вы можете добавить это в файл .d.ts
:
declare module '*';
Выгода (и минус) этого заключается в том, что вы можете импортировать абсолютно все, и TS будет компилироваться.
d.ts
? Вы должны предоставить какую-либо конфигурацию, такую как typeRoots
?
.d.ts
в тех же местах, что и обычные файлы .ts
: как указано «files», «include» и «exclude» в tsconfig.json
. Я бы не рекомендовал использовать typeRoots
для этой цели: он предназначен для размещения модулей внешнего типа (то есть node_modules/@types
), а не отдельных файлов .d.ts
.
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"]
в compilerOptions
(с соответствующим относительным путем к ваши папки), чтобы позволить TypeScript знать, где он может найти определения типов ваших библиотек и модулей и добавить новое свойство "exclude": ["../../node_modules", "../../typings"]
в файл. Вот пример того, как должен выглядеть ваш файл tsconfig.json:
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"sourceMap": true,
"outDir": "../dst/",
"target": "ESNEXT",
"typeRoots": [
"../../typings",
"../../node_modules/@types"
]
},
"lib": [
"es2016"
],
"exclude": [
"../../node_modules",
"../../typings"
]
}
Делая это, ошибка исчезнет, и вы сможете придерживаться последних правил ES6 и TypeScript.
Этот способ работает для меня:
1. добавьте свое собственное объявление в файл объявлений, такой как index.d.ts (возможно, в корне проекта)declare module Injector;
2. добавьте ваш index.d.js в tsconfig.json {
"compilerOptions": {
"strictNullChecks": true,
"moduleResolution": "node",
"jsx": "react",
"noUnusedParameters": true,
"noUnusedLocals": true,
"allowSyntheticDefaultImports":true,
"target": "es5",
"module": "ES2015",
"declaration": true,
"outDir": "./lib",
"noImplicitAny": true,
"importHelpers": true
},
"include": [
"src/**/*",
"index.d.ts", // declaration file path
],
"compileOnSave": false
}
У меня была та же проблема с использованием модуля узла с приложением реагирования, написанным на машинописи. Модуль был успешно установлен с помощью npm я --save my-module
. Он написан на javascript и экспортирует класс Client
.
С:
import * as MyModule from 'my-module';
let client: MyModule.Client = new MyModule.Client();
Компиляция завершается с ошибкой:
Could not find a declaration file for module 'my-module'.
'[...]/node_modules/my-module/lib/index.js' implicitly has an 'any' type.
Try 'npm install @types/my-module' if it exists or add a new declaration (.d.ts) file containing 'declare module 'my-module';'
@types/my-module
не существует, поэтому я добавил файл my-module.d.ts
рядом с файлом, в который импортируется my-module
, с предложенной строкой. Я тогда получил ошибку:
Namespace '"my-module"' has no exported member 'Client'.
Клиент фактически экспортируется и работает нормально, если я использую его в приложении js. Кроме того, предыдущее сообщение говорит мне, что компилятор ищет нужный файл (/node_modules/my-module/lib/index.js
определен в my-module/package.json
элемент "main"
).
Я решил проблему, указав компилятор я не заботиться о неявном any
, то есть, я поставил в false
следующую строку tsconfig.json
файла:
"noImplicitAny": false,
Я тоже это получал, на какое-то время я был сбит с толку, даже с уже установленным модулем и типами и перезагружал мою IDE несколько раз.
В моем случае это исправляло завершение процессов терминала, удаление node_modules
, очистку кеша менеджера пакетов узлов и повторную install
затем перезагрузку редактора.
Я решил эту проблему просто так:
import * as foo from "foo";
В моем случае эта проблема возникла, когда я пытался использовать класс по умолчанию, экспортируемый библиотекой.
У меня была такая же проблема, и я решил ее, обновив tsconfig.json
compilerOptions
следующим образом:
{
"compilerOptions": {
...
"noImplicitAny": false,
...
},
"exclude": [
...
]
}