TypeScript 踩坑之旅

前提

由于最近在作一个 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,编译器会从当前目录开始去查找 tsconfig.json文件,逐级向上搜索父目录。

    • 不带任何输入文件的状况下调用 tsc,且使用命令行参数 --project(或-p)指定一个包含 tsconfig.json 文件的目录。

    • 当命令行上指定了输入文件时,tsconfig.json 文件会被忽略。

  • tsconfig.json - target & lib
    • 若是 .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 踩坑之旅

[译文]一步步构建发布一个 TypeScript NPM 包

npm install package-lock.json 的更新策略

[译]浏览器语言首选项

Date.prototype.toLocaleString()

相关文章
相关标签/搜索