我阅读了TypeScript模块解析的工作原理。

我有以下存储库:@tsstack/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/@tsstack/di/dist/index.js”隐式具有“any”类型。

然而,如果我按如下方式导入,那么一切都正常:

import {Injector} from '/path/to/node_modules/@ts-stack/di/dist/index.js';

我做错了什么?


对于安装自己的npm包的情况

如果您使用的是第三方软件包,请参阅下面的答案。

从package.json中的“main”:“dist/index.js”中删除.js。

"main": "dist/index",

还可以根据TypeScript文档在package.json中添加打字员:

"main": "dist/index",
"typings": "dist/index",

文件夹dist是TS编译器存储模块文件的位置。


还有两种解决方案

如果模块不是您的,请尝试从@types安装类型:

npm install -D @types/module-name

如果出现上述安装错误,请尝试更改import语句以要求:

// import * as yourModuleName from 'module-name';
const yourModuleName = require('module-name');

如果您正在导入一个第三方模块“foo”,该模块在库本身或@types/foo包(从DefinelyTyped存储库生成)中不提供任何类型,那么可以通过在扩展名为.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量相当少,那么这特别容易。


另一方面,如果您不关心外部库的打字员,并且希望将所有没有打字员的库作为任何库导入,则可以将其添加到扩展名为.d.ts的文件中:

declare module '*';

这样做的好处(也有缺点)是,您可以完全导入任何内容,TS将进行编译。


由于Javascript中缺少约束,TypeScript基本上是在实现规则并向代码中添加类型,以使代码更清晰、更准确。TypeScript要求您描述数据,以便编译器可以检查代码并查找错误。编译器将告诉您是否使用了不匹配的类型,是否超出了范围或试图返回不同的类型。因此,当您使用TypeScript的外部库和模块时,它们需要包含描述代码中类型的文件。这些文件被称为扩展名为d.ts的类型声明文件。npm模块的大多数声明类型都已编写,您可以使用npm install@types/module_name(其中module_name是要包含其类型的模块的名称)来包含它们。

但是,有些模块没有它们的类型定义,为了消除错误并使用import*作为“模块名”中的模块名导入模块,请在项目的根目录中创建一个文件夹类型,在其中创建一个带有模块名的新文件夹,并在该文件夹中创建模块名.d.ts文件并写入声明模块“模块名。”。之后,只需转到tsconfig.json文件,在compilerOptions中添加“typeRoots”:[“../../typings”,“../../node_modules/@types”](具有文件夹的正确相对路径),让TypeScript知道在哪里可以找到库和模块的类型定义,并在文件中添加一个新属性“exclude”:[。下面是一个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规则。


我也得到了这一点,让我困惑了一段时间,即使已经安装了模块和类型,并多次重新加载了IDE。

在我的案例中,解决方法是终止终端进程,删除node_modules,清除节点包管理器缓存,重新安装,然后重新加载编辑器。


我在使用节点模块和用typescript编写的react应用程序时遇到了同样的问题。使用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模块不存在,所以我在导入我的模块的文件旁边添加了一个my-module.d.ts文件,并添加了建议的行。然后我得到了错误:

Namespace '"my-module"' has no exported member 'Client'.

如果我在js应用程序中使用它,客户端实际上是导出的,并且正常工作。此外,前面的消息告诉我编译器正在查找正确的文件(/node_modules/my-module/lib/index.js是在my-modle/package.json“main”元素中定义的)。

我通过告诉编译器我不关心隐式的任何问题来解决这个问题,也就是说,我将tsconfig.json文件的以下行设置为false:

    "noImplicitAny": false,

这种方式对我有效:

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
    }

如果需要快速修复,只需将其添加到导入行之前:

// @ts-ignore

对于阅读本文的其他人,请尝试将.js文件重命名为.ts

编辑:您还可以将“allowJs”:true添加到tsconfig文件中。


不幸的是,包编写者是否对声明文件感到困扰,我们无法控制。我倾向于创建一个像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
  ]

只需使用require将其导入,如下代码所示:

var _ = require('your_module_name');

一个简单的解决方案:

// 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编译器会自动将其作为环境模块(不需要显式导入的模块)。一旦我们指定了导入。。。从…起该文件现在成为一个正常(ES6)模块,因此不会自动拾取。因此,如果您仍然希望它作为环境模块,请使用不同的导入样式,如下所示:

type MyType: import('3rd-party-module').SomeModuleType;

检查“tsconfig.json”文件中的编译选项“include”和“exclude”。如果它不存在,只需通过通知根目录来添加它们。

// tsconfig.json
{
  "compilerOptions": {
  ...
  "include": [
    "src", 
  ],
  "exclude": [
    "node_modules", 
  ]
}

我只是从“exclude”中删除了扩展语句“*.spec.ts”,就解决了这个愚蠢的问题,因为在这些文件中包含“import”时,总是会出现问题。


这就是我工作的方式。

在我的例子中,我使用了一个没有定义类型的库:react mobile datepicker

a.在/src中创建文件夹。在我的例子中,我使用了以下路径:/src/typengs/。

b.创建.dts文件。例如:/src/typerings/react-mobile-datepicker.dts

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.按照通常使用第三方库的方式导入类型。

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


如果您已经安装了模块,但仍然收到错误,一个简短而简单的解决方案是通过在该行上方添加以下行来忽略错误消息

// @ts-ignore: Unreachable code error

如果导入不适用于您

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;

就是这样。我在这个问题上纠结了两天,但最终得到了解决。


解决方案:您所要做的就是编辑TypeScript Config文件tsconfig.json,并添加一个新的键值对作为

"compilerOptions": {
"noImplicitAny": false
}

如果您在Webstorm中看到此错误,并且您刚刚安装了程序包,则可能需要重新启动typescript服务,然后它才会恢复。

打开帮助菜单查找操作搜索重新启动Typescript服务


@ktretyak和@Retsam的答案是正确的,但我想添加一个完整的实时示例以及我必须做的事情:

错误:

错误TS7016(TS)找不到模块的声明文件'反应区域选择'。'C:/Repo/node_modules/react region select/lib/RegionSelect.js'隐式具有“any”类型。尝试npm i--save dev@types/react region select(如果存在)或添加新声明包含“声明模块”的(.d.ts)文件

运行npm i--save dev@types/react region select时出现错误:

npm错误!代码E404npm错误!404未找到-GEThttps://registry.npmjs.org/@类型%2反应区域选择-未找到npm错误!404'@类型/react-region-select@latest'不是在npm注册表中。npm错误!404你应该让作者发布它(或者自己使用这个名字!)npm错误!404注意您也可以从npm tarball、文件夹、httpurl或giturl安装。

考虑到create-react-app创建了一个名为react-app-env.d.ts的文件,我尝试将声明模块放入“react region select”;但我还是收到了错误。

然后,我在src中创建了一个名为typings的新文件夹,以及名为react-region-select.dts的文件

declare module 'react-region-select';

这样做之后,错误消失了,我可以像文档所述那样导入它:

import RegionSelect from "react-region-select"; 

https://github.com/casavi/react-region-select


对我有用的是将依赖项安装为开发依赖项。上述禁用隐式类型检查的解决方案有效,但这使我无法利用严格类型代码。因此,您需要做的就是在所有的@types模块安装中附加--save-dev标志。希望这对你也有用


创建具有任意名称和.d.ts扩展名的文件。

例如:index.d.ts

将此文件名推送到tsconfig.json文件的include键下:

  "include": [
    "src",
    "index.d.ts"
  ]

您可能需要创建扩展名为.d.ts的文件。

将此文件名推送到tsconfig.json文件的include键下:

  "include": [
    "src",
    "index.d.ts"
  ]

这应该是工作


您所要做的就是编辑TypeScript Config文件(tsconfig.json),并添加一个新的键值对作为“noImplicitAny”:false


在许多项目中,我面临着许多包的相同问题。所以我创建了Declarator,一个自动生成类型声明的npm包。

它基本上通过在后台运行tsc-emitDeclarationOnly来工作。

您可以从npm安装它:

npm install --save-dev declarator
yarn add -D declarator

然后创建一个简单的声明器.json文件:

{
  "$schema": "https://raw.githubusercontent.com/ArthurFiorette/declarator/master/schema.json",
  "packages": ["package1","package2"]
}

并创建一个脚本来运行它:

使用postinstall脚本将在每次安装包时运行它,这可能很有用

{
  "scripts": {
    "postinstall": "declarator"
  }
}

它不会生成强大的类型,在这一过程中您可能会遇到许多类型,但使用它比不使用它要好得多

阅读更多信息:https://github.com/ArthurFiorette/declarator#readme


import { io, Socket,SocketIOClient } from 'socket.io-client';

在component.ts之上添加这个在我的案例中是有效的。


只需在项目的根目录中创建一个名为typings.d.ts的文件。在该文件中,只需添加declare module<module_name>。这里,module_name可以是要导入的任何模块的名称。最后,打开tsconfig.json文件,将文件typeings.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-with-out-type-declarations-in-a-typescript-project-3643490015f3


从Typescript文档中:

注意,“typings”字段与“type”同义,也可以使用。

还要注意,如果主声明文件名为index.d.ts,并且位于包的根目录(index.js旁边),则不需要标记types属性,尽管这样做是明智的。

由于某种原因,我的“types”属性指向一些main.d.ts。从package.json中删除该行,它开始工作。


基于Retsam的回答,您还可以在Declarations.d.ts文件中使用通配符(*)。例如,如果您试图导入一个文件,例如.css或.webp文件,可以在文件类型声明的开头放置一个*。看起来像这样⤵︎

declare module '*.webp';

现在,您可以导入所需的所有.web文件,而不会出现任何linting错误。


对于在React、tsconfig.json中遇到此错误的人,请设置

"compilerOptions" : {
  ...
  "strict": false,
  ...
}

React的create-React应用程序自动生成的配置将该标志设置为true


这对我有用。

// modules.d.ts 
declare module 'my-module';
// tsconfig.json 
{
  ...
  "include": [
    ...
    "src", "modules.d.ts"
  ]
}

// Import
import * as MyModule from 'my-module'
...
const theModule = MyModule()
...

我在angular项目中的uuid模块也遇到了同样的问题。

当然不是为了刺激,但在前一行加上“//@ts-ignore”很快就解决了我的问题。


在大多数情况下,您可能会为依赖项安装一个类型包,无论是哪种方式,都可以在tsconfig.json文件中添加allowJs->true


在我看来,解决这个问题的三种不同方法都不起作用。一旦在package.json中将“type”设置为“module”,那么它将符合ES module而不是CommonJS语法。我能够根据package.json设置使用ES模块语法来解决这个问题。

import ws from 'ws'

export const create = (/** @type {string} */ accessToken) => {
    const WebSocket = ws;
    return new WebSocket(endpoint, accessToken, sslOptions);
}

这样,您就可以在“ws”模块中使用WebSocket类。这是一个节点模块的示例,但基本上可以将任何类型的节点模块和函数放在其中。

下面这些对我不起作用:

npm安装-D@types/module名称const foo=require('模块名称');

// index.d.ts
declare module 'foo';

tsconfig.json中的配置

"noImplicitAny": true,
"allowJs": true