发布

现在你已经按照本指南的步骤编写了声明文件,是时候将其发布到 npm 了。你可以通过两种主要方式将声明文件发布到 npm:

¥Now that you have authored a declaration file following the steps of this guide, it is time to publish it to npm. There are two main ways you can publish your declaration files to npm:

  1. 与你的 npm 包打包

    ¥bundling with your npm package

  2. 在 npm 上发布到 @types 组织

    ¥publishing to the @types organization on npm.

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

¥If your types are generated by your source code, publish the types with your source code. Both TypeScript and JavaScript projects can generate types via declaration.

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

¥Otherwise, we recommend submitting the types to DefinitelyTyped, which will publish them to the @types organization on npm.

在你的 npm 包中包含声明

¥Including declarations in your npm package

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

¥If your package has a main .js file, you will need to indicate the main declaration file in your package.json file as well. Set the types property to point to your bundled declaration file. For example:

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

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

¥Note that the "typings" field is synonymous with types, and could be used as well.

依赖

¥Dependencies

所有依赖都由 npm 管理。确保你所依赖的所有声明包都在你的 package.json。例如,假设我们编写了一个使用 Browserify 和 TypeScript 的包。

¥All dependencies are managed by npm. Make sure all the declaration packages you depend on are marked appropriately in the "dependencies" section in your package.json. For example, imagine we authored a package that used Browserify and 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 打包了它的声明文件,因此不需要任何额外的依赖。

¥Here, our package depends on the browserify and typescript packages. browserify does not bundle its declaration files with its npm packages, so we needed to depend on @types/browserify for its declarations. typescript, on the other hand, packages its declaration files, so there was no need for any additional dependencies.

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

¥Our package exposes declarations from each of those, so any user of our browserify-typescript-extension package needs to have these dependencies as well. For that reason, we used "dependencies" and not "devDependencies", because otherwise our consumers would have needed to manually install those packages. If we had just written a command line application and not expected our package to be used as a library, we might have used devDependencies.

红旗

¥Red flags

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

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

¥Don’t use /// <reference path="..." /> in your declaration files.

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

请改用 /// <reference types="..." />

¥Do use /// <reference types="..." /> instead.

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

请确保重新访问 引用依赖 部分以获取更多信息。

¥Make sure to revisit the Consuming dependencies section for more information.

封装依赖声明

¥Packaging dependent declarations

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

¥If your type definitions depend on another package:

  • 不要将其与你的合并,将每个文件保存在自己的文件中。

    ¥Don’t combine it with yours, keep each in their own file.

  • 也不要复制包中的声明。

    ¥Don’t copy the declarations in your package either.

  • 如果它不打包其声明文件,请依赖 npm 类型声明包。

    ¥Do depend on the npm type declaration package if it doesn’t package its declaration files.

typesVersions 的版本选择

¥Version selection with typesVersions

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

¥When TypeScript opens a package.json file to figure out which files it needs to read, it first looks at a field called typesVersions.

文件夹重定向(使用 *

¥Folder redirects (using *)

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

¥A package.json with a typesVersions field might look like this:

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 文件夹中读取。

¥This package.json tells TypeScript to first check the current version of TypeScript. If it’s 3.1 or later, TypeScript figures out the path you’ve imported relative to the package, and reads from the package’s ts3.1 folder.

这就是 { "*": ["ts3.1/*"] } 的意思 - 如果你熟悉 路径映射,它的工作原理与此完全相同。

¥That’s what that { "*": ["ts3.1/*"] } means - if you’re familiar with path mapping, it works exactly like that.

在上面的示例中,如果我们从 "package-name" 导入,在 TypeScript 3.1 中运行时,TypeScript 将尝试从 [...]/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

¥In the above example, if we’re importing from "package-name", TypeScript will try to resolve from [...]/node_modules/package-name/ts3.1/index.d.ts (and other relevant paths) when running in TypeScript 3.1. If we import from package-name/foo, we’ll try to look for [...]/node_modules/package-name/ts3.1/foo.d.ts and [...]/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

¥What if we’re not running in TypeScript 3.1 in this example? Well, if none of the fields in typesVersions get matched, TypeScript falls back to the types field, so here TypeScript 3.0 and earlier will be redirected to [...]/node_modules/package-name/index.d.ts.

文件重定向

¥File redirects

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

¥When you want to only change the resolution for a single file at a time, you can tell TypeScript the file to resolve differently by passing in the exact filenames:

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

¥On TypeScript 4.0 and above, an import for "package-name" would resolve to ./index.d.ts and for 3.9 and below "./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

¥Note that redirections only affect the external API of a package; import resolution within a project is not affected by typesVersions. For example, a d.ts file in the previous example containing import * as foo from "./index" will still map to index.d.ts, not index.v3.d.ts, whereas another package importing import * as foo from "package-name" will get index.v3.d.ts.

匹配行为

¥Matching behavior

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

¥The way that TypeScript decides on whether a version of the compiler & language matches is by using Node’s semver ranges.

多个字段

¥Multiple fields

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

¥typesVersions can support multiple fields where each field name is specified by the range to match on.

{
"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 及更高版本,但颠倒顺序可能会有不同的行为,因此上面的示例不会等同于以下示例。

¥Since ranges have the potential to overlap, determining which redirect applies is order-specific. That means in the above example, even though both the >=3.2 and the >=3.1 matchers support TypeScript 3.2 and above, reversing the order could have different behavior, so the above sample would not be equivalent to the following.

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

发布到 @types

¥Publish to @types

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

¥Packages under the @types organization are published automatically from DefinitelyTyped using the types-publisher tool. To get your declarations published as an @types package, please submit a pull request to DefinitelyTyped. You can find more details in the contribution guidelines page.