TypeScript 2:无类型 npm 模块的自定义类型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40222162/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 07:24:47  来源:igfitidea点击:

TypeScript 2: custom typings for untyped npm module

typescriptnpmtypescript-typings

提问by Jodiug

After trying suggestions posted in other places, I find myself unable to get a typescript project running that uses an untyped NPM module. Below is a minimal example and the steps that I tried.

在尝试了其他地方发布的建议后,我发现自己无法运行使用无类型 NPM 模块的打字稿项目。下面是一个最小的例子和我尝试过的步骤。

For this minimal example, we will pretend that lodashdoes not have existing type definitions. As such, we will ignore the package @types/lodashand try to manually add its typings file lodash.d.tsto our project.

对于这个最小的例子,我们将假装lodash没有现有的类型定义。因此,我们将忽略该包@types/lodash并尝试将其打字文件手动添加lodash.d.ts到我们的项目中。

Folder structure

文件夹结构

  • node_modules
    • lodash
  • src
    • foo.ts
  • typings
    • custom
      • lodash.d.ts
    • global
    • index.d.ts
  • package.json
  • tsconfig.json
  • typings.json
  • 节点模块
    • 洛达什
  • 源文件
  • 打字
    • 风俗
      • lodash.d.ts
    • 全球的
    • 索引.d.ts
  • 包.json
  • 配置文件
  • 打字.json

Next, the files.

接下来是文件。

File foo.ts

文件 foo.ts

///<reference path="../typings/custom/lodash.d.ts" />
import * as lodash from 'lodash';

console.log('Weeee');

File lodash.d.tsis copied directly from the original @types/lodashpackage.

文件lodash.d.ts直接从原始@types/lodash包中复制。

File index.d.ts

文件 index.d.ts

/// <reference path="custom/lodash.d.ts" />
/// <reference path="globals/lodash/index.d.ts" />

File package.json

文件 package.json

{
  "name": "ts",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "typings": "./typings/index.d.ts",
  "dependencies": {
    "lodash": "^4.16.4"
  },
  "author": "",
  "license": "ISC"
}

File tsconfig.json

文件 tsconfig.json

{
  "compilerOptions": {
    "target": "ES6",
    "jsx": "react",
    "module": "commonjs",
    "sourceMap": true,
    "noImplicitAny": true,
    "experimentalDecorators": true,
    "typeRoots" : ["./typings"],
    "types": ["lodash"]
  },
  "include": [
    "typings/**/*",
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

File typings.json

文件 typings.json

{
    "name": "TestName",
    "version": false,
    "globalDependencies": {
        "lodash": "file:typings/custom/lodash.d.ts"
    }
}

As you can see, I have tried many different ways of importing typings:

如您所见,我尝试了许多不同的导入类型的方法:

  1. By directly importing it in foo.ts
  2. By a typingsproperty in package.json
  3. By using typeRootsin tsconfig.jsonwith a file typings/index.d.ts
  4. By using an explicit typesin tsconfig.json
  5. By including the typesdirectory in tsconfig.json
  6. By making a custom typings.jsonfile and running typings install
  1. 通过直接导入 foo.ts
  2. typings物业在package.json
  3. 通过typeRootstsconfig.json文件中使用typings/index.d.ts
  4. 通过使用一个明确typestsconfig.json
  5. 通过将types目录包含在tsconfig.json
  6. 通过制作自定义typings.json文件并运行typings install

Yet, when I run Typescript:

然而,当我运行打字稿时:

E:\temp\ts>tsc
error TS2688: Cannot find type definition file for 'lodash'.

What am I doing wrong?

我究竟做错了什么?

回答by dtabuenc

Unfortunately these things are not currently very well documented, but even if you were able to get it working, let's go over your configuration so that you understand what each part is doing and how it relates to how typescript processes and loads typings.

不幸的是,这些东西目前没有很好的文档记录,但即使你能够让它工作,让我们回顾一下你的配置,以便你了解每个部分在做什么以及它如何与 typescript 处理和加载类型相关。

First let's go over the error you are receiving:

首先让我们回顾一下您收到的错误:

error TS2688: Cannot find type definition file for 'lodash'.

This error is actually not coming from your imports or references or your attempt to use lodash anywhere in your ts files. Rather it is coming from a misunderstanding of how to use the typeRootsand typesproperties, so let's go into a little more detail on those.

这个错误实际上不是来自您的导入或引用,也不是您尝试在 ts 文件中的任何地方使用 lodash。相反,它来自对如何使用typeRootstypes属性的误解,所以让我们更详细地了解这些。

The thing about typeRoots:[]and types:[]properties is that they are NOTgeneral-purpose ways to load arbitrary declaration (*.d.ts) files.

关于typeRoots:[]types:[]属性的事情是它们不是加载任意声明 ( *.d.ts) 文件的通用方法。

These two properties are directly related to the new TS 2.0 feature which allows packaging and loading typing declarations from NPM packages.

这两个属性与新的 TS 2.0 特性直接相关,该特性允许从NPM 包打包和加载类型声明。

This is very important to understand, that these work only with folders in NPM format (i.e. a folder containing a package.jsonor index.d.ts).

理解这一点非常重要,这些仅适用于 NPM 格式的文件夹(即包含package.jsonindex.d.ts的文件夹)。

The default for typeRootsis:

默认为typeRoots

{
   "typeRoots" : ["node_modules/@types"]
}

By default this means that typescript will go into the node_modules/@typesfolder and try to load every sub-folder it finds there as a npm package.

默认情况下,这意味着 typescript 将进入该node_modules/@types文件夹并尝试加载它在那里找到的每个子文件夹作为npm package

It is important to understand that this will fail if a folder does not have an npm package-like structure.

重要的是要了解,如果文件夹没有类似 npm 包的结构,这将失败。

This is what is happening in your case, and the source of your initial error.

这就是您的情况发生的情况,也是您初始错误的根源。

You have switched typeRoot to be:

您已将 typeRoot 切换为:

{
    "typeRoots" : ["./typings"]
}

This means that typescript will now scan the ./typingsfolder for subfoldersand try to load each subfolder it finds as an npm module.

这意味着打字稿现在将扫描./typings文件夹中的子文件夹并尝试将它找到的每个子文件夹加载为 npm 模块。

So let's pretend you just had typeRootssetup to point to ./typingsbut did not yet have any types:[]property setup. You would likely see these errors:

因此,让我们假设您刚刚typeRoots设置要指向./typings但还没有任何types:[]属性设置。您可能会看到以下错误:

error TS2688: Cannot find type definition file for 'custom'.
error TS2688: Cannot find type definition file for 'global'.

This is because tscis scanning your ./typingsfolder and finding the sub-folders customand global. It then is trying to interpret these as npm package-type typing, but there is no index.d.tsor package.jsonin these folders and so you get the error.

这是因为tsc正在扫描您的./typings文件夹并找到子文件夹customglobal. 然后它试图将这些解释为 npm 包类型类型,但是这些文件夹中没有index.d.tspackage.json,因此您会收到错误消息。

Now let's talk a bit about the types: ['lodash']property you are setting. What does this do? By default, typescript will load allsub-folders it finds within your typeRoots. If you specify a types:property it will only load those specific sub-folders.

现在让我们谈谈types: ['lodash']您正在设置的属性。这有什么作用?默认情况下,打字稿将加载所有子文件夹,找到你的范围内typeRoots。如果您指定一个types:属性,它只会加载那些特定的子文件夹。

In your case you are telling it to load the ./typings/lodashfolder but it doesn't exist. This is why you get:

在您的情况下,您告诉它加载./typings/lodash文件夹但它不存在。这就是为什么你得到:

error TS2688: Cannot find type definition file for 'lodash'

So let's summarize what we've learned. Typescript 2.0 introduced typeRootsand typesfor loading declaration files packaged in npm packages. If you have custom typings or single loose d.tsfiles that are not contained withing a folder following npm package conventions, then these two new properties are not what you want to use. Typescript 2.0 does not really change how these would be consumed. You just have to include these files in your compilation context in one of the many standard ways:

所以让我们总结一下我们学到的东西。Typescript 2.0 引入typeRootstypes用于加载打包在npm 包中的声明文件。如果您有自定义类型或单个松散d.ts文件,这些文件不包含在遵循 npm 包约定的文件夹中,那么这两个新属性不是您想要使用的。Typescript 2.0 并没有真正改变它们的使用方式。您只需要以多种标准方式之一将这些文件包含在您的编译上下文中:

  1. Directly including it in a .tsfile: ///<reference path="../typings/custom/lodash.d.ts" />

  2. Including ./typings/custom/lodash.d.tsin your files: []property.

  3. Including ./typings/index.d.tsin your files: []property (which then recursively includes the other typings.

  4. Adding ./typings/**to your includes:

  1. 直接将其包含在.ts文件中: ///<reference path="../typings/custom/lodash.d.ts" />

  2. 包括./typings/custom/lodash.d.ts在您的files: []财产中。

  3. 包括./typings/index.d.ts在您的files: []财产中(然后递归地包括其他类型。

  4. 添加./typings/**到您的includes:

Hopefully, based on this discussion you'll be able to tell why the changes you mad to your tsconfig.jsonmade things work again.

希望基于此讨论,您将能够说出为什么您对tsconfig.json所做的更改所做的更改再次起作用。

EDIT:

编辑:

One thing that I forgot to mention is that typeRootsand typesproperty are really only useful for the automaticloading of global declarations.

我忘记提及的一件事是,typeRootstypes属性实际上仅对自动加载全局声明有用。

For example if you

例如,如果你

npm install @types/jquery

And you are using the default tsconfig, then that jquery types package will be loaded automatically and $will be available throughout all your scripts wihtout having to do any further ///<reference/>or import

并且您正在使用默认的 tsconfig,然后该 jquery 类型包将自动加载,并且$可以在您的所有脚本中使用而无需进一步执行///<reference/>import

The typeRoots:[]property is meant to add additional locations from where type packageswill be loaded frrom automatically.

typeRoots:[]属性旨在添加额外的位置,从中自动加载类型

The types:[]property's primary use-case is to disable the automatic loading behavior (by setting it to an empty array), and then only listing specific types you want to include globally.

types:[]属性的主要用例是禁用自动加载行为(通过将其设置为空数组),然后仅列出要全局包含的特定类型。

The other way to load type packages from the various typeRootsis to use the new ///<reference types="jquery" />directive. Notice the typesinstead of path. Again, this is only useful for global declaration files, typically ones that don't do import/export.

从各种加载类型包的另一种方法typeRoots是使用新///<reference types="jquery" />指令。请注意types代替path。同样,这仅对全局声明文件有用,通常是那些不做import/export.

Now, here's one of the things that causes confusion with typeRoots. Remember, I said that typeRootsis about the global inclusion of modules. But @types/folderis also involved in standard module-resolution (regardless of your typeRootssetting).

现在,这是导致与typeRoots. 请记住,我说过这typeRoots是关于模块的全局包含。但@types/folder也涉及标准模块分辨率(无论您的typeRoots设置如何)。

Specifically, explicitly importing modules always bypasses all includes, excludes, files, typeRootsand typesoptions. So when you do:

具体来说,明确导入模块总是绕过所有 includesexcludesfilestypeRootstypes选项。所以当你这样做时:

import {MyType} from 'my-module';

All the above mentioned properties are completely ignored. The relevant properties during module resolutionare baseUrl, paths, and moduleResolution.

上面提到的所有属性都被完全忽略了。在相关性模块的分辨率baseUrlpathsmoduleResolution

Basically, when using nodemodule resolution, it will start searching for a file name my-module.ts, my-module.tsx, my-module.d.tsstarting at the folder pointed to by your baseUrlconfiguration.

基本上,当使用node模块解析时,它将开始搜索文件名my-module.ts, my-module.tsxmy-module.d.ts从您的baseUrl配置指向的文件夹开始。

If it doesn't find the file, then it will look for a folder named my-moduleand then search for a package.jsonwith a typingsproperty, if there is package.jsonor no typingsproperty inside telling it which file to load it will then search for index.ts/tsx/d.tswithin that folder.

如果它没有找到该文件,那么它将查找一个名为的文件夹my-module,然后搜索package.json具有typings属性的a ,如果里面有package.json或没有typings属性告诉它要加载哪个文件,它将index.ts/tsx/d.ts在该文件夹中搜索。

If that's still not successful it will search for these same things in the node_modulesfolder starting at your baseUrl/node_modules.

如果这仍然不成功,它将在node_modules以您的baseUrl/node_modules.

In addition, if it doesn't find these, it will search baseUrl/node_modules/@typesfor all the same things.

此外,如果它没有找到这些,它会搜索baseUrl/node_modules/@types所有相同的东西。

If it still didn't find anything it will start going to the parent directory and search node_modulesand node_modules/@typesthere. It will keep going up the directories until it reaches the root of your file system (even getting node-modules outside your project).

如果它仍然没有找到任何东西,它将开始转到父目录node_modulesnode_modules/@types在那里搜索。它将继续向上目录,直到它到达您的文件系统的根目录(甚至在您的项目之外获取节点模块)。

One thing I want to emphasize is that module resolution completely ignores any typeRootsyou set. So if you configured typeRoots: ["./my-types"], this will not get searched during explicit module resolution. It only serves as a folder where you can put global definition files you want to make available to the whole application without further need to import or reference.

我想强调的一件事是模块分辨率完全忽略typeRoots您设置的任何内容。因此,如果您配置了typeRoots: ["./my-types"],则不会在显式模块解析期间进行搜索。它仅用作一个文件夹,您可以在其中放置要提供给整个应用程序的全局定义文件,而无需进一步导入或引用。

Lastly, you can override the module behavior with path mappings (i.e. the pathsproperty). So for example, I mentioned that any custom typeRootsis not consulted when trying to resolve a module. But if you liked you can make this behavior happen as so:

最后,您可以使用路径映射(即paths属性)覆盖模块行为。例如,我提到typeRoots在尝试解析模块时不会咨询任何自定义。但是如果你喜欢你可以让这种行为发生:

"paths" :{
     "*": ["my-custom-types/*", "*"]
 }

What this does is for all imports that match the left-hand side, try modifying the import as in the right side before trying to include it (the *on the right hand side represents your initial import string. For example if you import:

这样做是针对与左侧匹配的所有导入,尝试在尝试包含它之前修改右侧的导入(*右侧的代表您的初始导入字符串。例如,如果您导入:

import {MyType} from 'my-types';

It would first try the import as if you had written:

它会首先尝试导入,就像你写的一样:

import {MyType} from 'my-custom-types/my-types'

And then if it didn't find it would try again wihtout the prefix (second item in the array is just *which means the initial import.

然后如果它没有找到它会在没有前缀的情况下再次尝试(数组中的第二项就是*这意味着初始导入。

So this way you can add additional folders to search for custom declaration files or even custom .tsmodules that you want to be able to import.

因此,通过这种方式,您可以添加其他文件夹来搜索.ts您希望能够搜索的自定义声明文件甚至自定义模块import

You can also create custom mappings for specific modules:

您还可以为特定模块创建自定义映射:

"paths" :{
   "*": ["my-types", "some/custom/folder/location/my-awesome-types-file"]
 }

This would let you do

这会让你做

import {MyType} from 'my-types';

But then read those types from some/custom/folder/location/my-awesome-types-file.d.ts

但是然后从 some/custom/folder/location/my-awesome-types-file.d.ts

回答by Jodiug

Edit: out of date. Read the answer above.

编辑:过时了。阅读上面的答案。

I still don't understand this, but I found a solution. Use the following tsconfig.json:

我仍然不明白这一点,但我找到了解决方案。使用以下内容tsconfig.json

{
  "compilerOptions": {
    "target": "ES6",
    "jsx": "react",
    "module": "commonjs",
    "sourceMap": true,
    "noImplicitAny": true,
    "experimentalDecorators": true,
    "baseUrl": ".",
    "paths": {
      "*": [
        "./typings/*"
      ]
    }
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

Remove typings.jsonand everything under folder typingsexcept lodash.d.ts. Also remove all the ///...references

删除typings.json文件夹下的所有内容,typings除了lodash.d.ts. 同时删除所有///...引用

回答by Uday Sravan K

"*": ["./types/*"]This line in tsconfig paths fixed everything after 2 hours struggle.

"*": ["./types/*"]tsconfig 路径中​​的这一行在经过 2 小时的努力后修复了所有内容。

{
  "compilerOptions": {
    "moduleResolution": "node",
    "strict": true,
    "baseUrl": ".",
    "paths": {
      "*": ["./types/*"]
    },
    "jsx": "react",
    "types": ["node", "jest"]
  },
  "include": [
    "client/**/*",
    "packages/**/*"
  ],
  "exclude": [
    "node_modules/**/*"
  ]
}

typesis the folder name, which sits beside node_module i.e in the level of clientfolder (or srcfolder) types/third-party-lib/index.d.ts
index.d.tshas declare module 'third-party-lib';

types是文件夹名称,它位于 node_module 旁边,即在客户端文件夹(或src文件夹)的 types/third-party-lib/index.d.ts
级别中 index.d.tsdeclare module 'third-party-lib';

Note:The above config is an incomplete config, just to give an idea of how it looks like with types, paths, include and exclude in it.

注意:上面的配置是一个不完整的配置,只是为了让你了解它的类型、路径、包含和排除的样子。

回答by realharry

I know this is an old question, but typescript tooling has been continuously changing. I think the best option at this point is just rely on the "include" path settings in tsconfig.json.

我知道这是一个老问题,但打字稿工具一直在不断变化。我认为此时最好的选择就是依赖 tsconfig.json 中的“包含”路径设置。

  "include": [
        "src/**/*"
    ],

By default, unless you make particular changes, all *.ts and all *.d.ts files under src/will be automatically included. I think this is the easiest/best way to include custom type declaration files without customizing typeRootsand types.

默认情况下,除非您进行特定更改,否则src/将自动包含所有 *.ts 和所有 *.d.ts 文件。我想这是包括自定义类型的声明文件,而无需自定义最简单的/最佳途径typeRootstypes

Reference:

参考: