发布
现在,你已经按照本指南的步骤编写了声明文件,是时候将其发布到 npm 了。 你可以通过两种主要方式将声明文件发布到 npm:
- 与你的 npm 包捆绑在一起
- 发布到 npm 上的 @types 组织
如果你的类型是由源代码生成的,请将类型与源代码一起发布。TypeScript 和 JavaScript 项目都可以通过 declaration 生成类型。
否则,我们建议将类型提交到 DefinitelyTyped,它会将它们发布到 npm 上的 @types 组织。
在 npm 包中包含声明
如果你的包有一个主 .js 文件,你还需要在 package.json 文件中指明主声明文件。 设置 types 属性指向你打包的声明文件。 例如:
{
"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 的包。
{
"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 打包了其声明文件,因此不需要任何额外的依赖。
我们的包暴露了这些依赖的声明,因此任何使用我们 browserify-typescript-extension 包的用户也需要拥有这些依赖。 因此,我们使用了 "dependencies" 而不是 "devDependencies",否则我们的消费者将需要手动安装这些包。 如果我们只是编写一个命令行应用程序,并且不希望我们的包被用作库,我们可能会使用 devDependencies。
警示标志
/// <reference path="..." />
不要在你的声明文件中使用 /// <reference path="..." />。
/// <reference path="../typescript/lib/typescriptServices.d.ts" />
....要改用 /// <reference types="..." />。
/// <reference types="typescript" />
....请务必重新查看使用依赖项部分以获取更多信息。
打包依赖声明
如果你的类型定义依赖于另一个包:
- 不要将其与你的包合并,应将每个包放在自己的文件中。
- 也不要将声明复制到你的包中。
- 要依赖 npm 类型声明包(如果它没有打包其声明文件)。
使用 typesVersions 进行版本选择
当 TypeScript 打开一个 package.json 文件以确定需要读取哪些文件时,它首先会查看一个名为 typesVersions 的字段。
文件夹重定向(使用 *)
一个带有 typesVersions 字段的 package.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 以不同的方式解析该文件:
{
"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",
"types": "./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",
"types": "./index.d.ts",
"typesVersions": {
// 注意:这不起作用!
">=3.1": { "*": ["ts3.1/*"] },
">=3.2": { "*": ["ts3.2/*"] }
}
}发布到 @types
@types 组织下的包是通过 types-publisher 工具从 DefinitelyTyped 自动发布的。 要将你的声明作为 @types 包发布,请向 DefinitelyTyped 提交拉取请求。 你可以在贡献指南页面找到更多详细信息。