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
TypeScript 2: custom typings for untyped npm module
提问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 lodash
does not have existing type definitions. As such, we will ignore the package @types/lodash
and try to manually add its typings file lodash.d.ts
to 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
- custom
- 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.ts
is copied directly from the original @types/lodash
package.
文件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:
如您所见,我尝试了许多不同的导入类型的方法:
- By directly importing it in
foo.ts
- By a
typings
property inpackage.json
- By using
typeRoots
intsconfig.json
with a filetypings/index.d.ts
- By using an explicit
types
intsconfig.json
- By including the
types
directory intsconfig.json
- By making a custom
typings.json
file and runningtypings install
- 通过直接导入
foo.ts
- 由
typings
物业在package.json
- 通过
typeRoots
在tsconfig.json
文件中使用typings/index.d.ts
- 通过使用一个明确
types
的tsconfig.json
- 通过将
types
目录包含在tsconfig.json
- 通过制作自定义
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 typeRoots
and types
properties, so let's go into a little more detail on those.
这个错误实际上不是来自您的导入或引用,也不是您尝试在 ts 文件中的任何地方使用 lodash。相反,它来自对如何使用typeRoots
和types
属性的误解,所以让我们更详细地了解这些。
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.json或index.d.ts的文件夹)。
The default for typeRoots
is:
默认为typeRoots
:
{
"typeRoots" : ["node_modules/@types"]
}
By default this means that typescript will go into the node_modules/@types
folder 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 ./typings
folder for subfoldersand try to load each subfolder it finds as an npm module.
这意味着打字稿现在将扫描./typings
文件夹中的子文件夹并尝试将它找到的每个子文件夹加载为 npm 模块。
So let's pretend you just had typeRoots
setup to point to ./typings
but 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 tsc
is scanning your ./typings
folder and finding the sub-folders custom
and global
. It then is trying to interpret these as npm package-type typing, but there is no index.d.ts
or package.json
in these folders and so you get the error.
这是因为tsc
正在扫描您的./typings
文件夹并找到子文件夹custom
和global
. 然后它试图将这些解释为 npm 包类型类型,但是这些文件夹中没有index.d.ts
或package.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/lodash
folder 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 typeRoots
and types
for loading declaration files packaged in npm packages. If you have custom typings or single loose d.ts
files 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 引入typeRoots
并types
用于加载打包在npm 包中的声明文件。如果您有自定义类型或单个松散d.ts
文件,这些文件不包含在遵循 npm 包约定的文件夹中,那么这两个新属性不是您想要使用的。Typescript 2.0 并没有真正改变它们的使用方式。您只需要以多种标准方式之一将这些文件包含在您的编译上下文中:
Directly including it in a
.ts
file:///<reference path="../typings/custom/lodash.d.ts" />
Including
./typings/custom/lodash.d.ts
in yourfiles: []
property.Including
./typings/index.d.ts
in yourfiles: []
property (which then recursively includes the other typings.Adding
./typings/**
to yourincludes:
直接将其包含在
.ts
文件中:///<reference path="../typings/custom/lodash.d.ts" />
包括
./typings/custom/lodash.d.ts
在您的files: []
财产中。包括
./typings/index.d.ts
在您的files: []
财产中(然后递归地包括其他类型。添加
./typings/**
到您的includes:
Hopefully, based on this discussion you'll be able to tell why the changes you mad to your tsconfig.json
made things work again.
希望基于此讨论,您将能够说出为什么您对tsconfig.json
所做的更改所做的更改再次起作用。
EDIT:
编辑:
One thing that I forgot to mention is that typeRoots
and types
property are really only useful for the automaticloading of global declarations.
我忘记提及的一件事是,typeRoots
和types
属性实际上仅对自动加载全局声明有用。
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 typeRoots
is to use the new ///<reference types="jquery" />
directive. Notice the types
instead 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 typeRoots
is about the global inclusion of modules. But @types/folder
is also involved in standard module-resolution (regardless of your typeRoots
setting).
现在,这是导致与typeRoots
. 请记住,我说过这typeRoots
是关于模块的全局包含。但@types/folder
也涉及标准模块分辨率(无论您的typeRoots
设置如何)。
Specifically, explicitly importing modules always bypasses all includes
, excludes
, files
, typeRoots
and types
options. So when you do:
具体来说,明确导入模块总是绕过所有 includes
,excludes
,files
,typeRoots
和types
选项。所以当你这样做时:
import {MyType} from 'my-module';
All the above mentioned properties are completely ignored. The relevant properties during module resolutionare baseUrl
, paths
, and moduleResolution
.
上面提到的所有属性都被完全忽略了。在相关性模块的分辨率是baseUrl
,paths
和moduleResolution
。
Basically, when using node
module resolution, it will start searching for a file name my-module.ts
, my-module.tsx
, my-module.d.ts
starting at the folder pointed to by your baseUrl
configuration.
基本上,当使用node
模块解析时,它将开始搜索文件名my-module.ts
, my-module.tsx
,my-module.d.ts
从您的baseUrl
配置指向的文件夹开始。
If it doesn't find the file, then it will look for a folder named my-module
and then search for a package.json
with a typings
property, if there is package.json
or no typings
property inside telling it which file to load it will then search for index.ts/tsx/d.ts
within 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_modules
folder 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/@types
for 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_modules
and node_modules/@types
there. It will keep going up the directories until it reaches the root of your file system (even getting node-modules outside your project).
如果它仍然没有找到任何东西,它将开始转到父目录node_modules
并node_modules/@types
在那里搜索。它将继续向上目录,直到它到达您的文件系统的根目录(甚至在您的项目之外获取节点模块)。
One thing I want to emphasize is that module resolution completely ignores any typeRoots
you 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 paths
property). So for example, I mentioned that any custom typeRoots
is 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 .ts
modules 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.json
and everything under folder typings
except 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.ts有declare 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 typeRoots
and types
.
默认情况下,除非您进行特定更改,否则src/
将自动包含所有 *.ts 和所有 *.d.ts 文件。我想这是包括自定义类型的声明文件,而无需自定义最简单的/最佳途径typeRoots
和types
。
Reference:
参考: