Skip to content
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待

发布

现在,你已经按照本指南的步骤编写了声明文件,是时候将其发布到 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 可以支持多个字段,每个字段名由要匹配的范围指定。

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

jsonc
{
  "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 提交拉取请求。 你可以在贡献指南页面找到更多详细信息。