既然你已经按照本指南的步骤编写了声明文件,现在是时候将它发布到 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:
- 与你的 npm 包打包
- 在 npm 上发布到 @types organization。
如果你的类型是由源代码生成的,请将类型与源代码一起发布。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,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 的 "dependencies" 部分中被适当标记。例如,假设我们创建了一个使用 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"}}
在这里,我们的包依赖于 browserify 和 typescript 包。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:
- 不要和你自己的合并,每个都保存在自己的文件中。
- 也不要复制你包里的声明。
- 如果 npm 类型声明包没有打包它的声明文件,就要依赖它。
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 的影响。例如,前面例子中的一个 d.ts 文件包含 import * as foo from "./index",仍然会映射到 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 可以支持多个字段,每个字段名称由要匹配的范围指定。
{"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-publisher 工具 自动发布的。 要将你的声明发布为 @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.