这是一个 高质量 的 TypeScript 类型定义的仓库。
你可以去看其他语言的 README,英语,西班牙语,韩语,俄罗斯语,葡萄牙语,意大利语,日语!
这个部分会跟踪仓库和发布过程的运行状况。 这可能会对在 PRs 和包中遇到任何问题的贡献者有所帮助。
- 最近的构建都具有完善的 类型标注:
- 所有的包基于 typescript@next 版本都有完善的类型标注:
- 所有的包都会在1小时30分钟内 发布到 npm:
- typescript-bot 在 Definitely Typed 一直处于活跃状态
如果这里面的任何内容出现问题或者失败的情况,请在 the Definitely Typed channel on the TypeScript Community Discord server 提出问题。
可以查看 TypeScript 手册。
这是首选方法。它仅适用于 TypeScript 2.0+ 的用户。例如:
npm install --save-dev @types/node
编译器中会自动引入这些类型。
如果你的项目没有使用模块系统的话,你可能需要使用 types
进行手动引用:
/// <reference types="node" />
可以在 手册 中查看更多信息。
对于 npm 包 "foo",它的类型定义的包名应该是 "@types/foo"。 如果没有找到你的包,请在 TypeSearch 查询。
如果你仍然没有找到它,请检查它是否 捆绑 了自己的类型。
这通常会通过 package.json
文件中的 "types"
或 "typings"
字段提供,
或者将包中包含类型定义的 ".d.ts" 文件手动通过 /// <reference path="" />
引入.
Definitely Typed 仅在发布时间小于 2 年的 TypeScript 版本上测试软件包。当前已测试 3.7 及更高版本。如果您使用的是 TypeScript 2.0 到 3.6,仍然可以尝试安装 @types 软件包,大多数软件包都不使用 TypeScript 的新特性。但是不能保证它们会起作用,这是支持窗口:
@types
软件包具有它们明确支持的 TypeScript 版本的标记,因此通常可以获取早于 2 年窗口的较早版本的软件包。例如,如果运行 npm dist-tags @types/react
,您能看到 TypeScript 2.5 最高支持 react@16.0 的类型定义,而 TypeScript 2.6 和 2.7 则最高支持 react@16.4:
Tag | Version |
---|---|
latest | 16.9.23 |
ts2.0 | 15.0.1 |
... | ... |
ts2.5 | 16.0.36 |
ts2.6 | 16.4.7 |
ts2.7 | 16.4.7 |
... | ... |
这些可以被 TypeScript 1.0 使用。
你可能需要手动添加 引用。
有赖像你这样的用户不断贡献,Definitely Typed 才能持续运作下去
在你向世界分享你的成果前,请务必自己试用一下。
你可以使用 module augmentation 添加新功能。
你也可以直接在 node_modules/@types/foo/index.d.ts
编辑类型,或者从那里复制它们并按照以下步骤操作。
在你的 tsconfig.json
中添加:
"baseUrl": "types",
"typeRoots": ["types"],
(你也可以使用 src/types
.)
创建包含模块 "foo" 声明的 types/foo/index.d.ts
.
你现在应该能够在你的代码中从 "foo"
导入,它会连接到你上面所定义的新的类型声明。
然后构建并运行代码确保你的类型定义与实际上发生的情况一致。
一旦你的真实代码中的类型定义通过测试,那么可以发起一个 PR, 然后按照下面的说明去 编辑一个现有包 或 创建一个新包。
一旦你的包测试通过,你可以在 Definitely Typed 分享它。
首先,fork 这个仓库,然后安装 node,并运行以下命令 npm install
。如果你使用的 npm
版本是 v7,你需要增加 --legacy-peer-deps
参数。
我们使用机器人来自动管理大量的库,你可以在 why and how here 查看更多细节。下面是一个简易的示意图,显示了一个 PR 的生命周期:
通常情况下,你会选择克隆整个项目代码到本地机器进行开发,但是项目现在包含 7000 多个类型定义包,全部下载无疑会花费很多时间,而且也不是很有必要。
为了便于管理,是否可以选择只克隆你需要的类型定义包呢?使用 git 的 sparse-checkout
,--filter
,和 --depth
特性能够达成这个目的,能够显著减少克隆代码的时间和提高 git 操作的性能。
:注意: 该特性需要至少 git 版本 2.27.0,这可能比大部分人安装的版本要更新,旧版本的 git 也有更复杂一点的方式能够实现局部克隆,但本文不涉及。
git clone --sparse --filter=blob:none --depth=1 <forkedUrl>
--sparse
告知 git 使用 sparse-checkout 方式,所以首次克隆的只有根部的文件。--filter=blob:none
将排除文件,只在需要时获取它们。--depth=1
可以通过阶段提交历史来进一步提高克隆速度,不过它可能会导致一些问题,见:here.
git sparse-checkout add types/<type> types/<dependency-type> ...
cd types/<package to edit>
- 作出修改之后,记得新增测试。 如果你进行了重大修改,不要忘记 更新主版本
- 你可能还想将自己添加到包头部的 "Definitions by" 部分。
- 这会导致一旦有人对该包发起 PR 或者 issue,都会通知你(通过你的 GitHub 用户名)。
- 通过将您的名字添加到行尾来执行此操作,比如
// Definitions by: Alice <https://github.com/alice>, Bob <https://github.com/bob>
. - 或者如果有多人,它也可以是多行的
// Definitions by: Alice <https://github.com/alice> // Bob <https://github.com/bob> // Steve <https://github.com/steve> // John <https://github.com/john>
- 就运行
npm test <package to test>
.
当你对现有的包发起 PR 的时候,请确保 dt-bot
会通知以前的作者。
如果没有,你可以在与 PR 关联的评论中手动去 @ 他们。
如果你是库作者并且你的包是用 TypeScript 编写的,那么请在你的包里 捆绑自动生成的声明文件 而不是发布到 Definitely Typed.
如果你要为 npm 包添加类型,请创建具有相同名字的目录。
如果你要添加类型的包不再 npm 上,请确保为它选择的名字不会与 npm 上面的包名冲突。
(你可以使用 npm info <my-package>
来检查 <my-package>
包是否存在。)
你的包应该具有这样的结构:
文件名 | 目的 |
---|---|
index.d.ts |
这里包含了包的类型声明。 |
<my-package>-tests.ts |
这里包含了测试类型的示例代码,此代码 不会 运行,但是它需要通过类型检查。 |
tsconfig.json |
这里允许你在包里运行 tsc . |
tslint.json |
启用 linting. |
如果你的 npm ≥ 5.2.0,运行 npx dts-gen --dt --name <my-package> --template module
来生成这些文件,否则就运行 npm install -g dts-gen
和 dts-gen --dt --name <my-package> --template module
.
可以在 dts-gen 查看所有的选项。
如果你除了 index.d.ts
以外还有别的 .d.ts
文件,请确保它们有在 index.d.ts
或测试文件中被引用。
Definitely Typed 的成员会定期查看新的 PRs,但是请记住当有许多其他 PRs 的时候,检查会变慢。
base64-js 是个很好的示例。
当一个包 捆绑 了自己的类型时,应该从 Definitely Typed 中删除类型避免被混淆。
你可以运行以下命令来删除它 npm run not-needed -- <typingsPackageName> <asOfVersion> [<libraryName>]
.
<typingsPackageName>
: 这是你要删除的目录名字.<asOfVersion>
: 将使用此版本将存根发布到@types/<typingsPackageName>
. 版本号应该高于当前发布的任何版本,并且应该是 npm 上的<libraryName>
版本。<libraryName>
: 替换 Definitely Typed 中类型的 npm 的包名。通常这与<typingsPackageName>
相同,这种情况下你可以忽略它。
Definitely Typed 中其他引用了删除包的任何包,都需要去更新去引用新的捆绑类型。
你可以查看 npm test
中的错误来获得此列表。
添加一个带有 "dependencies": { "<libraryName>": "x.y.z" }
的 package.json
文件,去修复这些错误。
比如:
{
"private": true,
"dependencies": {
"<libraryName>": "^2.6.0"
}
}
当你将 package.json
添加到 <libraryName>
依赖的时候,你还需要发起一个 PR, 将 <libraryName>
添加到 "DefinitelyTyped-tools" 中的 "allowedPackageJsonDependencies.txt".
如果这个包从未发布到 Definitely Typed 过,则不需要将其添加到 notNeededPackages.json
.
通过运行 npm test <package to test>
去测试你的改动,其中 <package to test>
是你的包名。
这个脚本使用了 dtslint 来对你的 dts 文件进行 TypeScript 编译测试.
如果你要为 npm 包添加类型,请创建具有相同名字的目录。
如果你要添加类型的包不再 npm 上,请确保为它选择的名字不会与 npm 上面的包名冲突。
(你可以使用 npm info <my-package>
来检查 <my-package>
包是否存在。)
If a non-npm package conflicts with an existing npm package try adding -browser to the end of the name to get <my-package>-browser
.
<my-package>-tests.ts
是你的类型定义项目的测试文件,它应该引入了你所编写的 *.ts
文件。
如果你在项目文件夹下看不到测试文件的话,你应该创建一份并编写测试用例。
测试文件应该对作为 @types/<my-package>
被交付的所有 *.d.ts
文件中被外部导出的 API 进行验证。
对 *.d.ts
的任何修改应该在 *.ts
中进行相应的更改,这样别人就不会意外的破坏你所依赖的代码。
举个例子,你为了 .d.ts
中的一个函数增加了一个新入参:
index.d.ts
:
- export function twoslash(body: string): string
+ export function twoslash(body: string, config?: { version: string }): string
<my-package>-tests.ts
:
import {twoslash} from "./"
// $ExpectType string
const result = twoslash("//")
+ // Handle options param
+ const resultWithOptions = twoslash("//", { version: "3.7" })
+ // When the param is incorrect
+ // $ExpectError
+ const resultWithOptions = twoslash("//", { })
如果你不知道从何开始,README 中的示例模块是个很好的参考。
你可以在根目录执行 npm test <package to test>
来 validate your changes 来验证你的更改。
若要声明的表达式是一个给定类型,请使用 $ExpectType
. 若要声明的表达式会导致编译错误,请使用 $ExpectError
.
// $ExpectType void
f(1);
// $ExpectError
f("one");
你可以查阅 dtslint 的 readme 去看更多详细信息。
The linter configuration file, tslint.json
should contain { "extends": "dtslint/dt.json" }
, and no additional rules.
If for some reason some rule needs to be disabled, disable it for that specific line using // tslint:disable-next-line:[ruleName]
— not for the whole package, so that disabling can be reviewed. (There are some legacy lint configs that have additional contents, but these should not happen in new work.)
tsconfig.json
should have noImplicitAny
, noImplicitThis
, strictNullChecks
, and strictFunctionTypes
set to true
.
你可以编辑 tsconfig.json
来增加新文件,增加 "target": "es6"
(异步函数需要),去增加 "lib"
,或者增加 "jsx"
编译选项。
通常你不需要它。
Definitely Typed 包的发布者会为在 Definitely Typed 之外没有依赖的包创建一个 package.json
文件。
package.json
包含了指定的而不是其他 @types
包的依赖。
当你发布包的时候会自动创建一个 package.json
的文件。
Pikaday 是一个好的例子。
包含 package.json
以便解析依赖。这有个 示例。
你还需要将依赖项添加到允许的包列表。
即使你编写自己的 package.json
文件,也只能指定依赖项。不允许使用其他字段,例如 "description"
.
该列表是人为更新,这让我们确保了 @types
包不会依赖恶意包。
在极少数情况下,@types
包会被删除,而不是源码包中提供的类型,并且你需要依赖旧的已经删除的 @types
包,你可以添加对 @types
包的依赖。
再添加到允许的包列表中时,请确保作出解释,以便让人工维护者知道发生了什么。
如果有一些文件需要包含在类型定义包中,但没有在测试文件或 index.d.ts
中被引用的话。你需要在 OTHER_FILES.txt
列出,一个文件占一行。
- 首先,请遵循 手册 的建议。
- 格式化:使用 4 个空格。 该仓库已经设置了 prettier,因此你只需要运行
npm run prettier -- --write path/to/package/**/*.ts
. 使用断言时,添加// prettier-ignore
将这几行标记为不需要格式化的代码:// prettier-ignore const incompleteThemeColorModes: Theme = { colors: { modes: { papaya: { // $ExpectError
function sum(nums: number[]): number
: 如果函数没有写入的参数,请使用ReadonlyArray
.interface Foo { new(): Foo; }
: 这定义了一个可实例化的类型,你可能需要的是declare class Foo { constructor(); }
.const Class: { new(): IClass; }
: 更推荐使用类声明class Class { constructor(); }
,而不是生成一个可实例化的类型。getMeAT<T>(): T
: 如果类型参数没有出现在函数的参数中,那么实际上你不需要这个泛型函数,你只是用了一个伪装的类型断言。 这种情况下最好使用真实的类型断言,类似这样,getMeAT() as number
. 类型参数可接受的示例:function id<T>(value: T): T;
. 类型参数不可接受的示例:function parseJson<T>(json: string): T;
. 有一个例外:new Map<string, number>()
是 OK 的。- 使用
Function
和Object
的类型基本上不是一个好方法。在 99% 的情况你可以去指定一个更具体的类型。比如,对于 Function,可以使用(x: number) => number
,对于Object
可以使用{ x: number, y: number }
. 对于不确定的类型,你需要使用any
而不是Object
. 只有当它类型确定且是某个对象的时候,使用object
, 而不是Object
或{ [key: string]: any }
. var foo: string | any
: 如果在联合类型中使用any
, 则结果始终为any
. 因此,即便类型中的string
部分看起来很有用,但实际上在类型检查方面与any
没有什么区别。根据你的意图,可以选择any
,string
, 或string | object
.
DT has the concept of "Definition Owners" which are people who want to maintain the quality of a particular module's types
- Adding yourself to the list will cause you to be notified (via your GitHub username) whenever someone makes a pull request or issue about the package.
- Your PR reviews will have a higher precedence of importance to the bot which maintains this repo.
- The DT maintainers are putting trust in the definition owners to ensure a stable eco-system, please don't add yourself lightly.
To Add yourself as a Definition Owner:
- Adding your name to the end of the line, as in
// Definitions by: Alice <https://github.com/alice>, Bob <https://github.com/bob>
. - Or if there are more people, it can be multiline
// Definitions by: Alice <https://github.com/alice> // Bob <https://github.com/bob> // Steve <https://github.com/steve> // John <https://github.com/john>
Once a week the Definition Owners are synced to the file .github/CODEOWNERS which is our source of truth.
master
分支会通过 DefinitelyTyped-tools 自动发布到 npm 上的 @types
.
这得看情况,但是大多数的 PR 会在一周内被合并。已经由定义包头部中的作者同意的 PR 通常会更快被合并。新定义类型的 PR 需要更多时间,因为它们需要维护人员花更多的时间去审核。每一个 PR 在合并之前都会由 TypeScript 或 Definitely Typed 的团队成员进行审核,所以请耐心等待这些因为人为因素导致的延迟。通过查看 New Pull Request Status Board,可以看到维护人员在开放 PRs 的工作进度。
npm 包应该会在几分钟内更新。如果已经超过了一小时,请在 the Definitely Typed channel on the TypeScript Community Discord server 上提及 PR 的编号,当前维护者会让团队成员去调查。
如果你引用的外部模块(使用 export
),那么请使用导入。
如果你引用的是环境模块(使用 declare module
, 或者只声明全局变量),那么请使用 <reference types="" />
.
有些包没有 tslint.json
文件,有些 tsconfig.json
文件缺少 "noImplicitAny": true
, "noImplicitThis": true
, 或 "strictNullChecks": true
.
当然它们是错误的,你可以通过发起 PR 来修复它们。
这里是 当前在请求的类型定义。
如果类型是 Web 标准的一部分,它们应该被贡献给 TSJS-lib-generator, 以便它们成为默认 lib.dom.d.ts
的一部分。
有些包,比如 chai-http, 导出一个函数。
使用 ES6 风格导入此模块的形式为 import * as foo from "foo";
, 会报下面的错误:
error TS2497: Module 'foo' resolves to a non-module entity and cannot be imported using this construct
通过将函数声明和同名的空命名空间合并可以抑制此错误,但不鼓励这种做法。 关于这个问题这是常被引用的 Stack Overflow 答案。
使用 import foo = require("foo");
语法导入模块更合适。
不过,如果你想使用像 import foo from "foo";
这样的默认导入,你有两个选择:
- 你可以使用
--allowSyntheticDefaultImports
的编译器选项 取决于你的模块运行是支持 non-ECMAScript 模块的互操作方案 ,即默认导入是否适用于你的环境(例如 Webpack, SystemJS, esm)。 - 你可以使用
--esModuleInterop
的编译器选项,如果你想使用 TypeScript 去处理 non-ECMAScript 的操作(从 Typescript 2.7 版本开始)。
跟之前的问题一样,参考使用 --allowSyntheticDefaultImports
或 --esModuleInterop
的编译器选项。
请不要更改准确的类型定义。
对于一个 npm 包,如果使用 node -p 'require("foo")'
去导入模块,那么 export =
是准确的。如果使用 node -p 'require("foo").default'
去导入模块,那么 export default
是准确的。
那么你必须在你的定义头部的最后一行添加注释(在 // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
之后):// Minimum TypeScript Version: 3.3
.
但是,如果你的项目在维护类型时需要在兼容 3.1 版本及以上的同时还要兼容 3.0 及以下的版本,那么你需要使用一个只有在 TypeScript 3.1 及以上版本的新特性 typesVersions
.
你可以在 官方 TypeScript 文档 中找到此功能的详细说明。
这里是个简短的说明,可以帮助您入门:
- 你必须在包定义中添加
package.json
文件,其中包含以下内容:
{
"private": true,
"types": "index",
"typesVersions": {
">=3.1.0-0": { "*": ["ts3.1/*"] }
}
}
-
在你的类型目录中创建一个在
typesVersions
字段中提到的子目录(在本例中为ts3.1/
),并为这个新版本添加特定的类型和测试。你不需要在ts3.1/
目录中任何一个文件添加传统的定义头部。 -
将
ts3.1/tsconfig.json
中baseUrl
和typeRoots
选项设置成正确的路径,它们应该如下所示:
{
"compilerOptions": {
"baseUrl": "../../",
"typeRoots": ["../../"]
}
}
这属于 TSJS-Lib-Generator. 请阅读那里的指南。
如果标准仍然是草案,则它属于这里。
使用以 dom-
开头的名称,并在头部中包含指向标准的链接作为项目的链接。
当它结束草案模式时,我们可以将它从 Definitely Typed 删除,并弃用相关的 @types
包。
注意:本节中的讨论假定你熟悉 语义版本控制
每个 Definitely Typed 包在发布到 npm 时都会进行版本控制。
DefinitelyTyped-tools (将 @types
包发布到 npm 的工具) 会通过将 major.minor
版本号写在 index.d.ts
文件的第一行来设置定义包的版本号。
例如,以下是 10.12.x
版本的 Node 的类型声明 的前几行:
// Type definitions for Node.js 10.12
// Project: https://nodejs.org/
// Definitions by: Microsoft TypeScript <https://github.com/Microsoft>
// Definitely Typed <https://github.com/DefinitelyTyped>
// Alberto Schiabel <https://github.com/jkomyno>
因为 10.12
在第一行的末尾,所以 @types/node
包的版本号也是 10.12.x
.
注意在 index.d.ts
文件的第一行注释中应该只包含 major.minor
的版本号(比如 10.12
),不应该包含补丁版本(例如 10.12.4
)。
这是因为只有主要版本号和次要版本号在库包和类型声明包之间相对齐。
类型声明包的补丁版本号(比如 10.12.0
中的 .0
)是由 Definitely Typed 初始化为 0,每次将新的 @types/node
包发布到对应库的同一主/次版本的 npm 是,他都会递增。
有时候,类型声明包的版本号和库包的版本号可能会不同步。 以下是一些常见的原因,是按照给库的用户带来不便的顺序排序的。 只有最后一种情况通常是有问题的。
- 如上所示,类型定义包的补丁版本与库包的补丁版本是无关的。这允许 Definitely Typed 安全地更新同一主/次版本的类型声明。
- 如果要更新包去获取新的功能,请不要忘记更新版本号以与该版本的库对齐。
- 类型定义包的更新落后于库的原因通常是因为库用户而不是维护者,他们在发布新特性从而更新了库的版本。因此,在愿意帮忙的社区成员发送 PR 去更新新的库版本对应的类型声明包之前,可能会有几天,几周甚至几个月的滞后。如果你深受此影响,你可以成为你想改变的,你可以去成为乐于助人的社区成员!
❗ 如果你想更新库的类型声明,请记住始终要在 index.d.ts
文件的第一行设置 major.minor
的版本号去匹配你正在记录的库版本! ❗
语义版本控制 要求具有重大修改的版本必须增加主版本号。
例如,一个库在 3.5.8
版本之后删除了一个公有的导出函数,那么它的下一版本必须升级到 4.0.0
.
此外,当该库的 4.0.0
版本发布时,它的类型声明包也需要更新到 4.0.0
, 包括对该库 API 的任何重大修改。
许多库都有大量的开发人员(包括使用该库作为依赖的其他包的维护者),他们不会立即迁移到具有重大改变的新版本。因为维护人员需要几个月的时间去重写代码以适应新版本。 与此同时,旧版本库的用户仍然想去更新旧版本的类型声明。
如果你打算继续更新旧版本库的类型声明,你可以创建一个以当前版本(很快就是旧版本)命名的新的子文件夹(比如 /v2/
),并将现有版本的文件都拷贝进去。
因为根文件夹始终包含最新版本的类型声明,所以你需要对旧版本子目录中的文件进行一些修改,以确保相对路径的引用指向子目录,而不是根目录。
- 更新
tsconfig.json
和tslint.json
中的相对路径。 - 添加路径映射规则以确保测试能够针对预期版本运行。
例如,history
库在 2.x
到 3.x
版本间引入了重大的修改。
因为许多用户仍然使用较老的 2.x
版本,维护人员想要将此库的类型声明更新到 3.x
, 需要在仓库里添加 v2
文件夹,里面包含了旧版本的类型声明。
在编写时,history v2 tsconfig.json
大致如下:
{
"compilerOptions": {
"baseUrl": "../../",
"typeRoots": ["../../"],
"paths": {
"history": [ "history/v2" ]
},
},
"files": [
"index.d.ts",
"history-tests.ts"
]
}
如果 Definitely Typed 上的其他包与新版本不兼容,你需要将路径映射到旧版本。 对于依赖于旧版本的包,你还需要递归地执行此操作。
例如,react-router
依赖 history@2
包,所以 react-router tsconfig.json
有一个映射到 "history": [ "history/v2" ]
的路径。
所以,react-router-bootstrap
(依赖 react-router
包)在它的依赖 react-router
更新到最新版本之前,也需要在它的 tsconfig.json
里添加相同的路径映射("history": [ "history/v2" ]
)。
此外,/// <reference types=".." />
不适用于路径映射,因此依赖需要使用 import
.
TypeScript 手册包含了优秀的 关于编写类型定义的概括信息, 以及 此示例定义文件,它展示了如何使用 ES6 模块语法创建定义,同时还指定了全局范围可用的对象。这个技术在 big.js
的定义 得到了实际证明。该库可以通过网页上的脚本标记全局加载,也可以通过 require 或者 ES6 风格的风格导入。
要测试你的类型定义是否能全局引用或者作为模块导入,请创建一个 test
文件,并在其中放置两个测试文件。一个命名为 YourLibraryName-global.test.ts
, 另一个为 YourLibraryName-module.test.ts
. 全局 测试文件应该根据如何在全局范围内库可用的网页上加载的脚本中使用它来执行定义,在这种情况下,你不应该制定 import 语句。模块 测试文件应该根据导入时的使用方式(包括 import
语句)来执行定义。如果在 tsconfig.json
文件中指定了 files
属性,请确保包含了两个测试文件。big.js
定义中还提供了一个 实际例子。
请注意,不需要在每个测试文件中完全执行定义 - 只需要在全局测试文件中测试全局可访问元素并在模块测试文件中完全执行定义,反之亦然。
作用域包 @foo/bar
的类型应该放在 types/foo__bar
中。请注意使用双下划线。
当使用 dts-gen
去构建作用域包时,必须在生成的 tsconfig.json
中手动调整 paths
属性去正确引用作用域包:
{
"paths":{
"@foo/*": ["foo__*"]
}
}
GitHub 不 支持 重命名文件的历史记录。请使用 git log --follow
命令代替。
该项目根据 MIT 许可证授权。
定义文件的版权分别对应于每个定义文件开头列出的每个贡献者。