typescript 编译器如何发现带有类型的 npm 包?

how does the typescript compiler discover npm packages with types?

打字稿编译器可以通过tsconfig.json配置。这也提供 settings for discovering type definition filestypeRoots 键。

默认:

By default all visible “@types” packages are included in your compilation. Packages in node_modules/@types of any enclosing folder are considered visible; specifically, that means packages within ./node_modules/@types/, ../node_modules/@types/, ../../node_modules/@types/, and so on.

If typeRoots is specified, only packages under typeRoots will be included

许多包在单独的 @types/<package-name> 包中提供它们的类型定义。 Jquery 例如。 同时,有些包附带了捆绑的类型定义,Firebase 就是这样做的。

为什么打字稿编译器可以在不编辑 typeRoots 设置的情况下获取 Firebase 定义?这些定义不在@types 中,据我所知,默认情况下不应使用这些定义。

在 TypeScript 的发布文档中,您会看到有两种方法可以为您的用户提供类型:https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html

  1. 与您的 npm 包捆绑在一起,或者
  2. 在 npm 上发布到 @types 组织。

Firebase 等更大的库有自己的类型,请参阅 packages/firebase/package.json#L58 or packages/database/package.json#L68.

Typescripts 读取正在编译的代码中引用的所有已安装包的 "typings" 中的那些引用文件。

typeRoots 和常规 import 'firebase' 的区别是:

  1. 一旦您在 typeRoot 中提供类型文件,这些类型将始终用于编译过程(自动包含)。这对于改变全局上下文的库来说非常有用,例如 jQuery、节点等。它们提供了否则不容易获取的全局函数。

  2. 您可以通过说 import {Foo} from 'bar' 明确导入它。如果 bar 包在其 package.json 中有一个 typing 属性,Typescript 将在 typeRoots 中额外选择它。

documentation 是这样说的:

Keep in mind that automatic inclusion is only important if you’re using files with global declarations (as opposed to files declared as modules). If you use an import "foo" statement, for instance, TypeScript may still look through node_modules & node_modules/@types folders to find the foo package.