尝试在 other places 中发布的建议后,我发现自己无法运行使用无类型 NPM 模块的 typescript 项目。下面是一个最小的例子和我尝试过的步骤。
对于这个最小的例子,我们假设 lodash
没有现有的类型定义。因此,我们将忽略包 @types/lodash
并尝试手动添加其打字文件 lodash.d.ts
到我们的项目。
文件夹结构
接下来是文件。
文件
foo.ts
///<reference path="../typings/custom/lodash.d.ts" />
import * as lodash from 'lodash';
console.log('Weeee');
文件
lodash.d.ts
直接复制原版@types/lodash
包。文件
index.d.ts
/// <reference path="custom/lodash.d.ts" />
/// <reference path="globals/lodash/index.d.ts" />
文件
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"
}
文件
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"
]
}
文件
typings.json
{
"name": "TestName",
"version": false,
"globalDependencies": {
"lodash": "file:typings/custom/lodash.d.ts"
}
}
如您所见,我尝试了许多不同的导入类型的方法:
foo.ts
中导入它typings
房产在package.json
typeRoots
在 tsconfig.json
带文件 typings/index.d.ts
types
在 tsconfig.json
types
目录在 tsconfig.json
typings.json
文件和运行 typings install
然而,当我运行 typescript 时:
E:\temp\ts>tsc
error TS2688: Cannot find type definition file for 'lodash'.
我做错了什么?
最佳答案
不幸的是,这些东西目前没有很好的文档记录,但即使你能够让它工作,让我们回顾一下你的配置,以便你了解每个部分在做什么以及它如何与 typescript 处理和加载类型相关。
首先让我们回顾一下您收到的错误:
error TS2688: Cannot find type definition file for 'lodash'.
这个错误实际上不是来自您的导入或引用,也不是您尝试在 ts 文件中的任何地方使用 lodash。相反,它来自对如何使用
typeRoots
和 types
属性的误解,所以让我们更详细地了解这些。关于
typeRoots:[]
和 types:[]
属性的事情是它们是 而不是 加载任意声明( *.d.ts
)文件的通用方法。这两个属性与新的 TS 2.0 特性直接相关,该特性允许从 NPM 包 打包和加载类型声明。
理解这一点非常重要,这些仅适用于 NPM 格式的文件夹(即包含 package.json 或 index.d.ts 的文件夹)。
typeRoots
的默认值是:{
"typeRoots" : ["node_modules/@types"]
}
默认情况下,这意味着 typescript 将进入
node_modules/@types
文件夹并尝试加载它在那里找到的每个子文件夹作为 npm 包 。重要的是要了解,如果文件夹没有类似 npm 包的结构,这将失败。
这就是您的情况发生的情况,也是您初始错误的根源。
您已将 typeRoot 切换为:
{
"typeRoots" : ["./typings"]
}
这意味着 typescript 现在将扫描
./typings
文件夹中的 子文件夹 并尝试将它找到的每个子文件夹加载为 npm 模块。因此,让我们假设您刚刚设置了
typeRoots
指向 ./typings
但还没有设置任何 types:[]
属性。您可能会看到以下错误:error TS2688: Cannot find type definition file for 'custom'.
error TS2688: Cannot find type definition file for 'global'.
这是因为
tsc
正在扫描您的 ./typings
文件夹并找到子文件夹 custom
和 global
。然后它试图将这些解释为 npm 包类型类型,但是这些文件夹中没有 index.d.ts
或 package.json
,因此您会收到错误消息。现在让我们谈谈您正在设置的
types: ['lodash']
属性。这有什么作用?默认情况下, typescript 将加载 在 typeRoots
中找到的所有 子文件夹。如果您指定 types:
属性,它只会加载那些特定的子文件夹。在您的情况下,您告诉它加载
./typings/lodash
文件夹,但它不存在。这就是为什么你得到:error TS2688: Cannot find type definition file for 'lodash'
所以让我们总结一下我们学到的东西。 Typescript 2.0 引入了
typeRoots
和 types
来加载打包在 npm 包中的声明文件。如果您有自定义类型或单个松散的 d.ts
文件,这些文件不包含在遵循 npm 包约定的文件夹中,那么这两个新属性不是您想要使用的。 Typescript 2.0 并没有真正改变它们的使用方式。您只需要以多种标准方式之一将这些文件包含在您的编译上下文中:.ts
文件中:///<reference path="../typings/custom/lodash.d.ts" />
./typings/custom/lodash.d.ts
属性中包含 files: []
。 ./typings/index.d.ts
属性中包含 files: []
(然后递归地包含其他类型。./typings/**
添加到您的 includes:
我们希望,在此基础上讨论,你就可以告诉为什么改变你疯了你
tsconfig.json
让事情再次合作。编辑:
我忘记提及的一件事是
typeRoots
和 types
属性实际上只对 自动 全局声明的加载有用。例如,如果你
npm install @types/jquery
并且您正在使用默认的 tsconfig,然后该 jquery 类型包将自动加载并且
$
将在您的所有脚本中可用,而无需执行任何进一步的 ///<reference/>
或 import
typeRoots:[]
属性旨在添加额外的位置,从那里自动加载类型包。types:[]
属性的主要用例是禁用自动加载行为(通过将其设置为空数组),然后仅列出要全局包含的特定类型。从各种
typeRoots
加载类型包的另一种方法是使用新的 ///<reference types="jquery" />
指令。注意 types
而不是 path
。同样,这仅对全局声明文件有用,通常是那些不执行 import/export
的文件。现在,这是导致与
typeRoots
混淆的一件事。记住,我说过 typeRoots
是关于模块的全局包含。但是 @types/folder
也参与标准模块解析(无论您的 typeRoots
设置如何)。具体来说,显式导入模块总是会绕过所有
includes
、 excludes
、 files
、 typeRoots
和 types
选项。所以当你这样做时:import {MyType} from 'my-module';
上面提到的所有属性都被完全忽略了。 模块解析 期间的相关属性是
baseUrl
、 paths
和 moduleResolution
。基本上,当使用
node
模块解析时,它将开始搜索文件名 my-module.ts
、 my-module.tsx
、 my-module.d.ts
,从您的 baseUrl
配置指向的文件夹开始。如果它没有找到文件,那么它会寻找一个名为
my-module
的文件夹,然后搜索一个带有 package.json
属性的 typings
,如果里面有 package.json
或没有 typings
属性告诉它要加载哪个文件,然后搜索 index.ts/tsx/d.ts
在那个文件夹内。如果仍然不成功,它将在
node_modules
文件夹中从您的 baseUrl/node_modules
开始搜索这些相同的内容。此外,如果没有找到这些,它将搜索
baseUrl/node_modules/@types
以查找所有相同的内容。如果它仍然没有找到任何东西,它将开始转到父目录并在那里搜索
node_modules
和 node_modules/@types
。它将继续向上目录,直到它到达您的文件系统的根目录(甚至在您的项目之外获取节点模块)。我想强调的一件事是模块解析完全忽略您设置的任何
typeRoots
。因此,如果您配置了 typeRoots: ["./my-types"]
,则在显式模块解析期间不会搜索到它。它仅用作一个文件夹,您可以在其中放置要提供给整个应用程序的全局定义文件,而无需进一步导入或引用。最后,您可以使用路径映射(即
paths
属性)覆盖模块行为。例如,我提到在尝试解析模块时不会咨询任何自定义 typeRoots
。但是如果你喜欢你可以让这种行为发生:"paths" :{
"*": ["my-custom-types/*", "*"]
}
这样做是针对与左侧匹配的所有导入,尝试在尝试包含它之前修改右侧的导入(右侧的
*
表示您的初始导入字符串。例如,如果您导入:import {MyType} from 'my-types';
它会首先尝试导入,就像你写的一样:
import {MyType} from 'my-custom-types/my-types'
然后如果它没有找到它会在没有前缀的情况下再次尝试(数组中的第二项只是
*
,这意味着初始导入。因此,通过这种方式,您可以添加其他文件夹来搜索自定义声明文件,甚至是您希望能够
.ts
的自定义 import
模块。您还可以为特定模块创建自定义映射:
"paths" :{
"*": ["my-types", "some/custom/folder/location/my-awesome-types-file"]
}
这会让你做
import {MyType} from 'my-types';
但是然后从
some/custom/folder/location/my-awesome-types-file.d.ts
读取这些类型
关于 typescript 2 : custom typings for untyped npm module,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40222162/