我阅读了 TypeScript module resolution 的工作原理。
我有以下存储库:@ts-stack/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
在我的 package.json 中,我写了 "main": "dist/index.js"
。
在 Node.js 中一切正常,但 TypeScript:
import {Injector} from '@ts-stack/di';
找不到模块“@ts-stack/di”的声明文件。 '/path/to/node_modules/@ts-stack/di/dist/index.js' 隐含地具有 'any' 类型。
然而,如果我按如下方式导入,那么一切正常:
import {Injector} from '/path/to/node_modules/@ts-stack/di/dist/index.js';
我究竟做错了什么?
这是另外两个解决方案
当模块不是您的时 - 尝试从 @types
安装类型:
npm install -D @types/module-name
如果出现上述安装错误 - 尝试将 import
语句更改为 require
:
// import * as yourModuleName from 'module-name';
const yourModuleName = require('module-name');
如果您在库本身或 @types/foo
包(从 DefinitelyTyped 存储库生成)中导入不提供任何类型的第三方模块 'foo'
,则可能会出现此错误通过在具有 .d.ts
扩展名的文件中声明模块来离开。 TypeScript 在查找普通 .ts
文件的相同位置查找 .d.ts
文件:如 tsconfig.json
中的“files”、“include”和“exclude”下指定的。
// 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
?
.ts
文件的相同位置查找 .d.ts
文件:如 tsconfig.json
中指定的“文件”、“包含”和“排除”。我不建议为此目的使用 typeRoots
:这是用于外部类型模块(即 node_modules/@types
)的位置,而不是单独的 .d.ts
文件。
declare module '...'
作为 module.d.ts
文件中的第一行代码,并在模块块中包含所有导入,而不是在它之前。在我这样做之前,编译器说它找不到模块。
declare module '*'
会确保只编译没有类型的包,还是会干扰有类型的包?
如果您需要快速修复,只需在导入行之前添加:
// @ts-ignore
error Do not use "// @ts-ignore" comments because they suppress compilation errors @typescript-eslint/ban-ts-ignore
// @ts-ignore
之前添加 /* eslint-disable */
以禁用 eslint,然后在问题代码行之后添加 /* eslint-enable */
以重新启用文件其余部分的 eslint。
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
对于您正在安装自己的 npm 包的情况
如果您使用第三方软件包,请参阅 my answer below。
从 package.json
中的 "main": "dist/index.js"
中删除 .js
。
"main": "dist/index",
还要添加 typings
in package.json
per the TypeScript docs:
"main": "dist/index",
"typings": "dist/index",
文件夹 dist
是 TS 编译器存储模块文件的位置。
dist
文件夹(或项目中的整个 node_modules
)的旧内容,然后再次运行您的捆绑程序。即使在此编辑之后,我仍然在 dist
中有旧的 index.js
,这对我造成了警告。
typings
不正确。我进行了一些更改以使答案更清晰。
rm -rf ./dist/* ; tsc
"main": "dist/index.js", "typings": "src/index"
。
由于 Javascript 缺乏约束,TypeScript 基本上是在实现规则并为您的代码添加类型以使其更清晰、更准确。 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
文件并在 compilerOptions
中添加 "typeRoots": [ "../../typings", "../../node_modules/@types"]
(使用正确的文件夹相对路径),让 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 规则。
index.d.ts
时,它才对我有用。除此之外,这是唯一对我有用的解决方案。
index.d.ts
)。对于那些使用默认应用程序结构 ng new app-name
的人,您可能需要您的路径具有一层,例如:"../node_modules"
和 "../typings"
等。另外,请确保 module-name
部分6} 语句与您在原始文件中导入它的方式完全相同。例如:在我的情况下,它必须是:declare module 'videojs-record/dist/videojs.record.js'
,因为这就是我在原始文件中导入它的方式。
"include"
中有一个文件夹(我的应用程序/组件所在的位置)与 typings
文件夹所在的位置不同,那么我不需要添加 "excludes":...
部分对吗?
对于其他阅读本文的人,请尝试将您的 .js 文件重命名为 .ts
编辑:您还可以将 "allowJs": true
添加到您的 tsconfig 文件中。
allowJs
设置为 true
但它不起作用
"allowJs": true
为我工作,谢谢
这种方式对我有用:
1.在index.d.ts等声明文件中添加自己的声明(可能在项目根目录下)
declare module 'Injector';
2. 将你的 index.d.ts 添加到 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
}
typings
的文件夹。在里面我添加了 .d.ts
文件
不幸的是,包编写者是否会为声明文件而烦恼,这不在我们的掌控之中。我倾向于做的是有一个像 index.d.ts
这样的文件,其中包含来自各种包的所有缺少的声明文件:
索引.d.ts:
declare module 'v-tooltip';
declare module 'parse5';
declare module 'emoji-mart-vue-fast';
并在您的 tsconfig.js
中引用它:
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx",
"index.d.ts" // this
]
只需在项目的根目录中创建一个名为 typings.d.ts
的文件。在此文件中只需添加 declare module <module_name>
。这里,module_name
可以是您要导入的任何模块的名称。最后,打开 tsconfig.json
文件并将文件 typings.d.ts
包含在名为 include array
的数组中。
// typings.d.ts
declare module 'abc-module';
// tsconfig.json
{
...
"include": [
"src", "typings.d.ts"
]
}
// BOOM, Problem solved!!!
这种技术为您的模块提供了一个名为“any”的类型。欲了解更多信息:https://medium.com/@steveruiz/using-a-javascript-library-without-type-declarations-in-a-typescript-project-3643490015f3
这就是我让它工作的方式。
在我的例子中,我使用了一个没有定义类型的库:react-mobile-datepicker
一个。在 /src
内创建一个文件夹。在我的例子中,我使用了这个路径:/src/typings/
。
湾。创建一个 .d.ts
文件。对于我的示例:/src/typings/react-mobile-datepicker.d.ts
C。我使用以下代码来扩展其属性并使其类型安全:
declare module 'react-mobile-datepicker' {
class DatePicker extends React.Component<DatePickerProps, any> {}
interface DatePickerProps {
isPopup?: boolean;
theme?: string;
dateConfig?: DatePickerConfig;
}
export interface DatePickerConfig {
prop1: number;
pro2: string;
}
export default DatePicker;
}
d。像通常在使用 3rd 方库的地方一样导入您的类型。
import DatePicker, { DatePickerConfig, DatePickerConfigDate } from 'react-mobile-datepicker';
e.更改 tsconfig.json
并添加这段代码:
{
"compilerOptions": {
//...other properties
"typeRoots": [
"src/typings",
"node_modules/@types"
]
}}
我用作来源的文章的链接:
https://templecoding.com/blog/2016/03/31/creating-typescript-typings-for-existing-react-components
https://www.credera.com/insights/typescript-adding-custom-type-definitions-for-existing-libraries
解决方案:您所要做的就是编辑您的 TypeScript 配置文件 tsconfig.json
并添加一个新的键值对作为
"compilerOptions": {
"noImplicitAny": false
}
一个简单的修复:
// example.d.ts
declare module 'foo';
如果你想声明一个对象的接口(推荐用于大型项目),你可以使用:
// example.d.ts
declare module 'foo'{
// example
export function getName(): string
}
怎么用?简单的..
const x = require('foo') // or import x from 'foo'
x.getName() // intellisense can read this
我在这里尝试了一切,但对我来说这是一个完全不同的问题:我必须从我的 *.d.ts
中删除任何导入语句:
import { SomeModuleType } from '3rd-party-module';
删除错误后消失...
澄清:当我们在 *.d.ts
文件中声明模块时,Typescript 编译器会自动将其作为 ambient 模块(您不需要导入的模块)明确)。一旦我们指定了 import ... from ...
,文件现在就变成了一个普通的 (ES6) 模块,因此不会被自动拾取。因此,如果您仍然希望它充当 ambient 模块,请使用不同的导入样式,如下所示:
type MyType: import('3rd-party-module').SomeModuleType;
检查 "tsconfig.json"
文件中的编译选项 "include"
和 "exclude"
。如果它不存在,只需通过通知您的 root 目录来添加它们。
// tsconfig.json
{
"compilerOptions": {
...
"include": [
"src",
],
"exclude": [
"node_modules",
]
}
我只是通过从 "exclude"
中删除扩展语句 "*.spec.ts"
解决了我的愚蠢问题,因为在这些文件中包含 "import"
时,总是会出现问题。
如果您已经安装了模块并且仍然收到错误,一个简短而有效的解决方案是通过在该行上方添加以下行来忽略错误消息
// @ts-ignore: Unreachable code error
@ktretyak 和 @Retsam 的答案是正确的,但我想添加一个完整的实时示例以及我必须做的事情:
错误:
错误 TS7016 (TS) 找不到模块“react-region-select”的声明文件。 'C:/Repo/node_modules/react-region-select/lib/RegionSelect.js' 隐含了一个 'any' 类型。尝试 npm i --save-dev @types/react-region-select 如果它存在或添加一个包含`declare module的新声明(.d.ts)文件
运行 npm i --save-dev @types/react-region-select
给出错误:
npm 错误!代码 E404 npm 错误! 404 未找到 - 获取 https://registry.npmjs.org/@types%2freact-region-select - 未找到 npm 错误! 404 '@types/react-region-select@latest' 不在 npm 注册表中。 npm 错误! 404 你应该让作者发布它(或自己使用名称!)npm ERR! 404 请注意,您也可以从 npm tarball、文件夹、http url 或 git url 安装。
鉴于 create-react-app
创建了一个名为 react-app-env.d.ts
的文件,我尝试将 declare module 'react-region-select';
放入其中,但仍然收到错误消息。
然后我在 src
中创建了一个名为 typings
的新文件夹和一个名为 react-region-select.d.ts
的文件。在那里我声明了这样的模块:
declare module 'react-region-select';
这样做之后,错误消失了,我可以像文档所述那样导入它:
import RegionSelect from "react-region-select";
https://github.com/casavi/react-region-select
我在使用带有用打字稿编写的反应应用程序的节点模块时遇到了同样的问题。该模块已使用 npm i --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
的文件旁边添加了一个 my-module.d.ts
文件,其中包含建议的行。然后我得到了错误:
Namespace '"my-module"' has no exported member 'Client'.
如果我在 js 应用程序中使用它,客户端实际上已导出并正常工作。此外,上一条消息告诉我编译器正在查找正确的文件(/node_modules/my-module/lib/index.js
在 my-module/package.json
"main"
元素中定义)。
我通过告诉编译器我不关心隐式 any
解决了这个问题,也就是说,我将 tsconfig.json
文件的以下行设置为 false
:
"noImplicitAny": false,
我在许多项目中的许多软件包都面临同样的问题。所以我创建了 Declarator,这是一个自动生成类型声明的 npm 包。
它基本上通过在后台运行 tsc --emitDeclarationOnly
来工作。
你可以从 npm 安装它:
npm install --save-dev declarator
yarn add -D declarator
然后创建一个简单的 declarator.json
文件:
{
"$schema": "https://raw.githubusercontent.com/ArthurFiorette/declarator/master/schema.json",
"packages": ["package1","package2"]
}
并创建一个脚本来运行它:
使用 postinstall 脚本将在每次安装包时运行它,可能很有用
{
"scripts": {
"postinstall": "declarator"
}
}
它不会生成强大的类型,并且您可能会在此过程中遇到许多 any
类型,但有总比没有好得多
阅读更多:https://github.com/ArthurFiorette/declarator#readme
我也得到了这个,让我困惑了一段时间,即使模块和类型已经安装并重新加载了我的 IDE 几次。
在我的情况下修复它的是终止终端进程,删除 node_modules
,清除节点包管理器缓存并执行新的 install
,然后重新加载编辑器。
如果您在 Webstorm 中看到此错误,并且您刚刚安装了该软件包,则可能需要重新启动 typescript 服务,然后它才能将其拾取。
打开帮助菜单
查找操作
搜索重启 Typescript 服务
https://i.stack.imgur.com/NtIPY.png
https://i.stack.imgur.com/AbaFI.png
这对我有用。
// modules.d.ts
declare module 'my-module';
// tsconfig.json
{
...
"include": [
...
"src", "modules.d.ts"
]
}
// Import
import * as MyModule from 'my-module'
...
const theModule = MyModule()
...
对我有用的是将依赖项安装为开发依赖项。上述禁用隐式类型检查的解决方案有效,但这使我无法利用严格类型的代码。因此,您要做的就是将所有 @types 模块安装附加到 --save-dev 标志。希望对你也有用
在 Retsam's answer 的基础上,您还可以在 yourDeclarations.d.ts
文件中使用通配符 (*
)。例如,如果您尝试导入文件,例如 .css
或 .webp
文件,您可以在文件类型声明的开头放置一个 *
。它看起来像这样⤵︎
declare module '*.webp';
现在,您可以导入所有需要的 .webp
文件,而不会出现任何 linting 错误。
如果导入不适合您
import * as html2pdf from 'html2pdf.js';
注释代码,将下面的脚本文件保留在 index.html 中,如官方文档中给出的那样。
<script src="https://rawgit.com/eKoopmans/html2pdf/master/dist/html2pdf.bundle.min.js"></script>
并在您正在使用的组件中声明 html2pdf 变量。
declare var html2pdf: any;
而已。我被这个问题困了2天,但终于解决了。
创建具有任意名称和 .d.ts
扩展名的文件。
例如:index.d.ts
在 tsconfig.json
文件的 include
键下推送此文件名:
"include": [
"src",
"index.d.ts"
]
您是否需要创建扩展名为 .d.ts
的文件。
在 tsconfig.json
文件的 include
键下推送此文件名:
"include": [
"src",
"index.d.ts"
]
这应该是工作
从打字稿文档:
请注意,“typings”字段与“types”同义,也可以使用。
另请注意,如果您的主声明文件名为 index.d.ts 并且位于包的根目录(在 index.js 旁边),则不需要标记 types 属性,但建议这样做。
出于某种原因,我的“类型”属性指向一些 main.d.ts。从 package.json 中删除该行并开始工作。
在大多数情况下,您可能会为您的依赖项安装一个类型包,无论哪种方式,您都可以在 tsconfig.json 文件中添加 allowJs -> true
对于在 React 中遇到此错误的人,请在 tsconfig.json 中设置
"compilerOptions" : {
...
"strict": false,
...
}
React 的 create-react-app 自动生成的配置将该标志设置为 true
strict:false
有什么缺点吗?
您所要做的就是编辑您的 TypeScript 配置文件 (tsconfig.json) 并添加一个新的键值对作为 "noImplicitAny": false
npm install @types/node --save-dev
const mdbreact = require('mdbreact'); const { Button, Card, CardBody, CardText, CardTitle, CardImage } = mdbreact;
const yourModuleName = require('module-name');