由于最近在作一个 TypeScript NPM 第三方库,在网上看到一篇简单的搭建流程,因而打算翻译一下 - 译文。在跟着文中步骤搭建的时候踩了一些坑,在此记录一下。本人 TypeScript 新手,如如有理解不对的地方,欢迎评论👏。html
照着文章步骤一步步搭建的时候,当第一次执行 npm run build
时,能正常运行;当只下载完 jest
以后再次运行 npm run build
报以下错:node
tsc node_modules/@types/babel__template/index.d.ts:16:28 — error TS2583: Cannot find name ‘Set’. Do you need to change your target library? Try changing the lib compiler option to es2015 or later.
16 placeholderWhitelist?: Set;
Found 1 error.
复制代码
个人 node, npm, tsc 的版本分别是:git
node -v // v8.12.0
npm -v // v6.4.1
tsc -v // v3.4.5
复制代码
项目代码:github.com/irenetang19…es6
Q1:为何我在 tsconfig.json
中已经 exclude node_modules了,tsc 仍是执行到 node_modules/@types 中去了?github
Q2:为何在 src 目录下新建一个 index.d.ts 声明文件不会被编译?typescript
先回顾下 tsconfig.jsonexpress
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"declaration": true,
"outDir": "./lib",
"strict": true
},
"include": ["./src"],
"exclude": ["node_modules", "**/__tests__/*"]
}
复制代码
Answer 1npm
基于上面的配置,即便设置了 exclude: ["node_modules"]
也不能阻止 tsc 编译 ./node_modules/@types 里的内容。缘由摘自官网 TypeScript - types and typeRoots,以下:json
默认全部可见的 @types 包会在编译过程当中被包含进来。 ./node_modules/@types 文件夹下以及它们子文件夹下的全部包都是可见的。也就是说, ./node_modules/@types/,../node_modules/@types/和 ../../node_modules/@types/ 等等。浏览器
若是指定了 typeRoots,只有 typeRoots下面的包才会被包含进来。 好比:
{
"compilerOptions": {
"typeRoots" : ["./typings"]
}
}
复制代码
这个配置文件会包含全部 ./typings 下面的包,而不包含 ./node_modules/@types 里面的包。
若是指定了 types,只有被列出来的包才会被包含进来。 好比:
{
"compilerOptions": {
"types" : ["node", "lodash", "express"]
}
}
复制代码
这个 tsconfig.json 文件将仅会包含 ./node_modules/@types/node,./node_modules/@types/lodash 和 ./node_modules/@types/express。 ./node_modules/@types/* 里面的其它包不会被引入进来。
指定 "types": [] 来禁用自动引入 @types 包。
注意,自动引入只在你使用了全局的声明(相反于模块)时是重要的。 若是你使用 import "foo" 语句,TypeScript 仍然会查找 node_modules 和 node_modules/@types 文件夹来获取 foo 包。
再来看看报的错 Cannot find name 'Set'。从上一个问题的回答中咱们已经知道在当前 tsconfig.json 的配置下, ./node_modules/@types 下的声明文件在运行 tsc 的时候是会被编译的,之因此报 Can not find name 'Set' 是由于 Set 是 ES6 的语法特性,而 tsconfig.json 中指定的 "target": "es5",而且没有指定 lib 的话,默认的 lib 是 DOM,ES5,ScriptHost,因此 tsc 不能正确的编译 Set。
解决这个报错的其中一个简单的方法就是指定 "target": "es6" 或者 lib 加上 es6。但我以为不该该为了第三方库缺乏某个声明的问题而去修改项目中的 tsconfig.json,因此就有了第二种方式,在项目中添加一个声明文件,结果又出现了上面提到的 Q2。
Answer 2
先看一下 src 文件夹:
declare interface Set<T> {}
复制代码
一开始我觉得在 tsconfig.json 中已经 include src 了,因此 index.d.ts 应该会被编译,可是并无;若是把它的文件名改为 test.d.ts 就被编译了,神奇!!!
后来我在官网找到了这句话:
须要注意编译器不会去引入那些可能作为输出的文件;好比,假设咱们包含了index.ts,那么index.d.ts和index.js会被排除在外。 一般来说,不推荐只有扩展名的不一样来区分同目录下的文件。
也就是说,由于我在 src 下已经有 index.ts 了,因此 index.d.ts 被排除了;当我把文件名改为 test.d.ts 以后又能被包含了。
不带任何输入文件的状况下调用 tsc,编译器会从当前目录开始去查找 tsconfig.json文件,逐级向上搜索父目录。
不带任何输入文件的状况下调用 tsc,且使用命令行参数 --project(或-p)指定一个包含 tsconfig.json 文件的目录。
当命令行上指定了输入文件时,tsconfig.json 文件会被忽略。
若是 .ts 文件中使用了某些高于 target 指定的语法特性,那么就须要在 lib 中指定这些语法特性所在的 ES 版本。例如:tsconfig.json 中指定的 target 是 "es5",在 index.ts 文件中使用了 ES2015 的 Set 会提示以下错误:error TS2583: Cannot find name 'Set'。解决这个错误有三种办法:
在 lib 中添加 "es6"
{
target: "es5",
compilerOptions: {
"lib": ["es6"]
}
}
复制代码
将 target 改为 es6
{
target: "es6"
}
复制代码
添加一个声明文件,如上缺乏 Set 声明,就在声明文件中写 Set 声明。注意文件名命名,不要踩了上面提到的坑。
declare interface Set<T> {}
复制代码
[译文]一步步构建发布一个 TypeScript NPM 包