发布

按照本指南的步骤编写声明文件后,现在是将其发布到 npm 的时候了。有两种主要方法可以将声明文件发布到 npm

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

如果你的类型是由源代码生成的,请使用源代码发布类型。TypeScript 和 JavaScript 项目都可以通过 declaration 生成类型。

否则,我们建议将类型提交到 DefinitelyTyped,它会将类型发布到 npm 上的 @types 组织。

在 npm 包中包含声明

如果你的包有一个主 .js 文件,你还需要在 package.json 文件中指明主声明文件。将 types 属性设置为指向你的捆绑声明文件。例如

json
{
"name": "awesome",
"author": "Vandelay Industries",
"version": "1.0.0",
"main": "./lib/main.js",
"types": "./lib/main.d.ts"
}

请注意,"typings" 字段与 types 同义,也可以使用。

依赖项

所有依赖项都由 npm 管理。确保你依赖的所有声明包都已在 package.json 中的 "dependencies" 部分中做了适当标记。例如,假设我们编写了一个使用 Browserify 和 TypeScript 的包。

json
{
"name": "browserify-typescript-extension",
"author": "Vandelay Industries",
"version": "1.0.0",
"main": "./lib/main.js",
"types": "./lib/main.d.ts",
"dependencies": {
"browserify": "latest",
"@types/browserify": "latest",
"typescript": "next"
}
}

在此,我们的软件包依赖于browserifytypescript软件包。browserify不会将其声明文件与其 npm 软件包捆绑在一起,因此我们需要依赖@types/browserify来进行声明。另一方面,typescript会打包其声明文件,因此无需任何其他依赖项。

我们的软件包公开每个软件包的声明,因此我们browserify-typescript-extension软件包的任何用户都需要同时具有这些依赖项。出于这个原因,我们使用了"dependencies"而不是"devDependencies",否则我们的使用者将需要手动安装这些软件包。如果我们刚刚编写了一个命令行应用程序,并且不希望我们的软件包被用作库,我们可能已经使用了devDependencies

危险信号

/// <reference path="..." />

不要在声明文件中使用/// <reference path="..." />

ts
/// <reference path="../typescript/lib/typescriptServices.d.ts" />
....

改为使用/// <reference types="..." />

ts
/// <reference types="typescript" />
....

请务必重新访问使用依赖项部分以获取更多信息。

打包依赖声明

如果你的类型定义依赖于另一个软件包

  • 不要将其与您的文件合并,让每个文件都保持在自己的文件中。
  • 不要复制包中的声明。
  • 依赖 npm 类型声明包,如果它不打包其声明文件。

使用 typesVersions 进行版本选择

当 TypeScript 打开 package.json 文件以找出它需要读取哪些文件时,它首先会查看一个名为 typesVersions 的字段。

文件夹重定向(使用 *

带有 typesVersions 字段的 package.json 可能如下所示

json
{
"name": "package-name",
"version": "1.0.0",
"types": "./index.d.ts",
"typesVersions": {
">=3.1": { "*": ["ts3.1/*"] }
}
}

package.json 告诉 TypeScript 首先检查 TypeScript 的当前版本。如果它是 3.1 或更高版本,TypeScript 就会找出您相对于包导入的路径,并从包的 ts3.1 文件夹中读取。

这就是 { "*": ["ts3.1/*"] } 的含义 - 如果您熟悉 路径映射,它的工作方式完全相同。

在上面的示例中,如果我们从 "package-name" 导入,TypeScript 将尝试在 TypeScript 3.1 中运行时从 [...]/node_modules/package-name/ts3.1/index.d.ts(和其他相关路径)中解析。如果我们从 package-name/foo 导入,我们将尝试查找 [...]/node_modules/package-name/ts3.1/foo.d.ts[...]/node_modules/package-name/ts3.1/foo/index.d.ts

如果在这个示例中我们没有在 TypeScript 3.1 中运行,会怎样?好吧,如果 typesVersions 中的任何字段都没有匹配,TypeScript 将回退到 types 字段,因此这里的 TypeScript 3.0 和更早版本将被重定向到 [...]/node_modules/package-name/index.d.ts

文件重定向

当您只想一次更改单个文件的分辨率时,您可以通过传入确切的文件名来告诉 TypeScript 以不同的方式解析文件

json
{
"name": "package-name",
"version": "1.0.0",
"types": "./index.d.ts",
"typesVersions": {
"<4.0": { "index.d.ts": ["index.v3.d.ts"] }
}
}

在 TypeScript 4.0 及更高版本中,"package-name" 的导入将解析为 ./index.d.ts,而在 3.9 及更低版本中解析为 "./index.v3.d.ts

请注意,重定向仅影响包的外部 API;项目内的导入解析不受 typesVersions 影响。例如,在前面的示例中,包含 import * as foo from "./index"d.ts 文件仍将映射到 index.d.ts,而不是 index.v3.d.ts,而导入 import * as foo from "package-name" 的另一个包获取 index.v3.d.ts

匹配行为

TypeScript 决定编译器和语言版本是否匹配的方式是使用 Node 的 semver 范围

多个字段

typesVersions 可以支持多个字段,其中每个字段名称由要匹配的范围指定。

{
"name": "package-name",
"version": "1.0",
"": "./index.d.ts",
"typesVersions": {
">=3.2": { "*": ["ts3.2/*"] },
">=3.1": { "*": ["ts3.1/*"] }
}
}

由于范围有可能重叠,因此确定应用哪个重定向是特定于顺序的。这意味着在上面的示例中,即使 >=3.2>=3.1 匹配器都支持 TypeScript 3.2 及更高版本,但颠倒顺序可能会产生不同的行为,因此上面的示例不等于以下示例。

{
"name": "package-name",
"version": "1.0",
"": "./index.d.ts",
"typesVersions": {
// NOTE: this doesn't work!
">=3.1": { "*": ["ts3.1/*"] },
">=3.2": { "*": ["ts3.2/*"] }
}
}

发布到 @types

@types 组织下的包会使用 DefinitelyTyped 中的 types-publisher 工具 自动发布。若要将你的声明发布为 @types 包,请向 DefinitelyTyped 提交拉取请求。你可以在 贡献指南页面 中找到更多详细信息。

TypeScript 文档是一个开源项目。通过 发送拉取请求 来帮助我们改进这些页面 ❤

此页面的贡献者
MHMohamed Hegazy (55)
OTOrta Therox (21)
MBMateusz Burzyński (2)
RVRauno Viskus (2)
RCRyan Cavanaugh (2)
19+

上次更新:2024 年 3 月 21 日