由於最近在作一個 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 文件夾:
index.ts 是一個普通的 .ts 文件,tests 下是一些測試文件,index.d.ts 是我添加的聲明文件,內容以下: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 包