[英]TypeScript 2: custom typings for untyped npm module
在尝试了其他地方发布的建议后,我发现自己无法运行使用无类型 NPM 模块的打字稿项目。 下面是一个最小的例子和我尝试过的步骤。
对于这个最小的例子,我们将假设lodash
没有现有的类型定义。 因此,我们将忽略包@types/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
直接导入package.json
的typings
属性tsconfig.json
使用typeRoots
和文件typings/index.d.ts
tsconfig.json
使用显式types
tsconfig.json
包含types
目录typings.json
文件并运行typings.json
typings install
然而,当我运行打字稿时:
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"]
}
默认情况下,这意味着打字稿将进入node_modules/@types
文件夹并尝试加载它在那里找到的每个子文件夹作为npm package 。
重要的是要了解,如果文件夹没有类似 npm 包的结构,这将失败。
这就是您的情况发生的情况,也是您初始错误的根源。
您已将 typeRoot 切换为:
{
"typeRoots" : ["./typings"]
}
这意味着打字稿现在将扫描./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']
属性。 这有什么作用? 默认情况下,打字稿将加载它在typeRoots
找到的所有子文件夹。 如果你指定一个types:
属性,它只会加载那些特定的子文件夹。
在您的情况下,您告诉它加载./typings/lodash
文件夹,但它不存在。 这就是为什么你得到:
error TS2688: Cannot find type definition file for 'lodash'
所以让我们总结一下我们学到的东西。 Typescript 2.0 引入了typeRoots
和用于加载打包在npm 包中的声明文件的types
。 如果您有自定义类型或单个松散的d.ts
文件,这些文件不包含在遵循 npm 包约定的文件夹中,那么这两个新属性不是您想要使用的。 Typescript 2.0 并没有真正改变它们的使用方式。 您只需要以多种标准方式之一将这些文件包含在您的编译上下文中:
直接将其包含在.ts
文件中: ///<reference path="../typings/custom/lodash.d.ts" />
在您的files: []
包含./typings/custom/lodash.d.ts
files: []
属性。
在您的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
、 types
typeRoots
和types
选项。 所以当你这样做时:
import {MyType} from 'my-module';
上面提到的所有属性都被完全忽略了。 模块解析期间的相关属性是baseUrl
、 paths
和moduleResolution
。
基本上,当使用node
模块的分辨率,它会开始寻找一个文件名my-module.ts
, my-module.tsx
, my-module.d.ts
开始在文件夹由您指出baseUrl
配置。
如果它没有找到该文件,那么它会寻找一个名为my-module
的文件夹,然后搜索一个带有typings
属性的package.json
,如果里面有package.json
或没有typings
属性告诉它要加载哪个文件然后index.ts/tsx/d.ts
在该文件夹中搜索index.ts/tsx/d.ts
。
如果仍然不成功,它将在node_modules
文件夹中搜索这些相同的内容,从您的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'
然后如果它没有找到它会在没有前缀的情况下再次尝试(数组中的第二项只是*
这意味着初始导入。
因此,通过这种方式,您可以添加其他文件夹来搜索自定义声明文件,甚至是您希望能够import
自定义.ts
模块。
您还可以为特定模块创建自定义映射:
"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
读取这些类型
编辑:过时了。 阅读上面的答案。
我仍然不明白这一点,但我找到了解决方案。 使用以下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"
]
}
删除typings.json
文件夹下,一切都typings
,除了lodash.d.ts
。 同时删除所有///...
引用
"*": ["./types/*"]
tsconfig 路径中的这一行在经过 2 小时的努力后修复了所有内容。
{
"compilerOptions": {
"moduleResolution": "node",
"strict": true,
"baseUrl": ".",
"paths": {
"*": ["./types/*"]
},
"jsx": "react",
"types": ["node", "jest"]
},
"include": [
"client/**/*",
"packages/**/*"
],
"exclude": [
"node_modules/**/*"
]
}
types是文件夹名称,它位于 node_module 旁边,即在客户端文件夹(或src文件夹)的级别中types/third-party-lib/index.d.ts
index.d.ts已declare module 'third-party-lib';
注意:上面的配置是一个不完整的配置,只是为了让你了解它在类型、路径、包含和排除中的样子。
我知道这是一个老问题,但打字稿工具一直在不断变化。 我认为此时最好的选择就是依赖 tsconfig.json 中的“包含”路径设置。
"include": [
"src/**/*"
],
默认情况下,除非您进行特定更改,否则将自动包含src/
下的所有 *.ts 和所有 *.d.ts 文件。 我认为这是包含自定义类型声明文件而不自定义typeRoots
和types
的最简单/最好的方法。
参考:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.