We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
虽然 TypeScript 已经逐渐进入主流,但是市面上大部分库还是以 JavaScript 编写的,这个时候由于库没有像 TS 一样定义类型,因此需要一个声明文件来帮助库的使用者来获取库的类型提示,比如 JQuery 虽然是 js 编写的但是如果引入 @types/jquery 就可以获得以下效果:
@types/jquery
Github 上有一个库 DefinitelyTyped 它定义了市面上主流的JavaScript 库的 d.ts ,而且我们可以很方便地用 npm 引入这些 d.ts。
比如我们要安装 JQuery 的 d.ts:
npm install @types/jquery -save
在日常开发中我们建议直接使用 DefinitelyTyped 定义的 d.ts,但是依然有些情况下我们需要给自己的库编写 d.ts,或者没有第三方的 d.ts 提供,这个时候就需要什么自己编写 d.ts 文件了.
关键字 declare 表示声明的意思,我们可以用它来做出各种声明:
declare
declare var
declare function
declare class
declare enum
declare namespace
interface
type
declare var/let/const,全局变量的声明可以说是最简单的了,虽然 var/let/const 都可以使用的,但是通常情况下全局变量是不允许改动的,大多数情况下还是以 const 为主:
declare var/let/const
var/let/const
const
// src/jQuery.d.ts declare const jQuery: (selector: string) => any;
// src/jQuery.d.ts
declare const jQuery: (selector: string) => any;
declare function 用来声明全局函数:
// src/jQuery.d.ts declare function jQuery(selector: string): any;
declare function jQuery(selector: string): any;
declare class 用于声明全局类
// src/Person.d.ts declare class Person { name: string; constructor(name: string); say(): string; }
// src/Person.d.ts
declare class Person { name: string; constructor(name: string); say(): string; }
declare enum 是于声明全局枚举类型
// src/Directions.d.ts declare enum Directions { Up, Down, Left, Right }
// src/Directions.d.ts
declare enum Directions { Up, Down, Left, Right }
declare namespace,命名空间虽然在日常开发中已经不常见了,但是在 d.ts 文件编写时还是很常见的,它用来表示全局变量是一个对象,包含很多子属性。
比如 jQuery 是全局对象,而其包含一个 jQuery.ajax 用于处理 ajax 请求,这个时候命名空间就派上用场了:
jQuery
jQuery.ajax
// src/jQuery.d.ts declare namespace jQuery { function ajax(url: string, settings?: any): void; }
declare namespace jQuery { function ajax(url: string, settings?: any): void; }
除了全局变量之外,可能有一些类型我们也希望能暴露出来。
在类型声明文件中,我们可以直接使用 interface 或 type 来声明一个全局的接口或类型:
// src/jQuery.d.ts interface AjaxSettings { method?: 'GET' | 'POST' data?: any; } declare namespace jQuery { function ajax(url: string, settings?: AjaxSettings): void; }
interface AjaxSettings { method?: 'GET' | 'POST' data?: any; } declare namespace jQuery { function ajax(url: string, settings?: AjaxSettings): void; }
假如 jQuery 既是一个函数,可以直接被调用 jQuery('#foo'),又是一个对象,拥有子属性 jQuery.ajax()(事实确实如此),那么我们可以组合多个声明语句,它们会不冲突的合并起来:
jQuery('#foo')
jQuery.ajax()
// src/jQuery.d.ts declare function jQuery(selector: string): any; declare namespace jQuery { function ajax(url: string, settings?: any): void; }
declare function jQuery(selector: string): any; declare namespace jQuery { function ajax(url: string, settings?: any): void; }
// src/index.ts jQuery('#foo'); jQuery.ajax('/api/get_something');
// src/index.ts
jQuery('#foo'); jQuery.ajax('/api/get_something');
如果库的源码本身就是由 ts 写的,那么在使用 tsc 脚本将 ts 编译为 js 的时候,添加 declaration 选项,就可以同时也生成 .d.ts 声明文件了.
tsc
declaration
.d.ts
我们可以在命令行中添加 --declaration(简写 -d),或者在 tsconfig.json 中添加 declaration 选项.
--declaration
-d
tsconfig.json
这里以 tsconfig.json 为例:
{ "compilerOptions": { "module": "commonjs", "outDir": "lib", "declaration": true, } }
上例中我们添加了 outDir 选项,将 ts 文件的编译结果输出到 lib 目录下,然后添加了 declaration 选项,设置为 true,表示将会由 ts 文件自动生成 .d.ts 声明文件,也会输出到 lib 目录下.
我们为一个开源库编写了声明文件后应该如何发布?
目前有两个选择:
如果是手动写的声明文件,那么需要满足以下条件之一,才能被正确的识别:
package.json
types
typings
index.d.ts
main
第一种方式是给 package.json 中的 types 或 typings 字段指定一个类型声明文件地址。比如:
{ "name": "foo", "version": "1.0.0", "main": "lib/index.js", "types": "foo.d.ts", }
指定了 types 为 foo.d.ts 之后,导入此库的时候,就会去找 foo.d.ts 作为此库的类型声明文件了。
foo.d.ts
typings 与 types 一样,只是另一种写法。
如果没有指定 types 或 typings,那么就会在根目录下寻找 index.d.ts 文件,将它视为此库的类型声明文件。
如果没有找到 index.d.ts 文件,那么就会寻找入口文件(package.json 中的 main 字段指定的入口文件)是否存在对应同名不同后缀的 .d.ts 文件。
比如 package.json 是这样时:
就会先识别 package.json 中是否存在 types 或 typings 字段。发现不存在,那么就会寻找是否存在 index.d.ts 文件。如果还是不存在,那么就会寻找是否存在 lib/index.d.ts 文件。假如说连 lib/index.d.ts 都不存在的话,就会被认为是一个没有提供类型声明文件的库了。
lib/index.d.ts
有的库为了支持导入子模块,比如 import bar from 'foo/lib/bar',就需要额外再编写一个类型声明文件 lib/bar.d.ts 或者 lib/bar/index.d.ts,这与自动生成声明文件类似,一个库中同时包含了多个类型声明文件。
import bar from 'foo/lib/bar'
lib/bar.d.ts
lib/bar/index.d.ts
如果我们是在给别人的仓库添加类型声明文件,但原作者不愿意合并 pull request,那么就需要将声明文件发布到 @types 下。
@types
与普通的 npm 模块不同,@types 是统一由 DefinitelyTyped 管理的。要将声明文件发布到 @types 下,就需要给 DefinitelyTyped 创建一个 pull-request,其中包含了类型声明文件,测试代码,以及 tsconfig.json 等。
pull-request 需要符合它们的规范,并且通过测试,才能被合并,稍后就会被自动发布到 @types 下。
在 DefinitelyTyped 中创建一个新的类型声明,需要用到一些工具,DefinitelyTyped 的文档中已经有了详细的介绍,这里就不赘述了,以官方文档为准。
本节我们学习了声明文件基本的编写技巧,接下来我们需要进行一次实战,为一个纯 JavaScript 编写的开源库编写 d.ts.
The text was updated successfully, but these errors were encountered:
No branches or pull requests
理论:如何为编写声明文件
虽然 TypeScript 已经逐渐进入主流,但是市面上大部分库还是以 JavaScript 编写的,这个时候由于库没有像 TS 一样定义类型,因此需要一个声明文件来帮助库的使用者来获取库的类型提示,比如 JQuery 虽然是 js 编写的但是如果引入
@types/jquery
就可以获得以下效果:使用第三方 d.ts
Github 上有一个库 DefinitelyTyped 它定义了市面上主流的JavaScript 库的 d.ts ,而且我们可以很方便地用 npm 引入这些 d.ts。
比如我们要安装 JQuery 的 d.ts:
在日常开发中我们建议直接使用 DefinitelyTyped 定义的 d.ts,但是依然有些情况下我们需要给自己的库编写 d.ts,或者没有第三方的 d.ts 提供,这个时候就需要什么自己编写 d.ts 文件了.
编写 d.ts 文件
关键字
declare
表示声明的意思,我们可以用它来做出各种声明:declare var
声明全局变量declare function
声明全局方法declare class
声明全局类declare enum
声明全局枚举类型declare namespace
声明(含有子属性的)全局对象interface
和type
声明全局类型声明变量
declare var/let/const
,全局变量的声明可以说是最简单的了,虽然var/let/const
都可以使用的,但是通常情况下全局变量是不允许改动的,大多数情况下还是以const
为主:声明函数
declare function
用来声明全局函数:声明类
declare class
用于声明全局类声明枚举
declare enum
是于声明全局枚举类型声明命名空间
declare namespace
,命名空间虽然在日常开发中已经不常见了,但是在 d.ts 文件编写时还是很常见的,它用来表示全局变量是一个对象,包含很多子属性。比如
jQuery
是全局对象,而其包含一个jQuery.ajax
用于处理 ajax 请求,这个时候命名空间就派上用场了:声明interface 和 type
除了全局变量之外,可能有一些类型我们也希望能暴露出来。
在类型声明文件中,我们可以直接使用 interface 或 type 来声明一个全局的接口或类型:
声明合并
假如 jQuery 既是一个函数,可以直接被调用
jQuery('#foo')
,又是一个对象,拥有子属性jQuery.ajax()
(事实确实如此),那么我们可以组合多个声明语句,它们会不冲突的合并起来:自动生成声明文件
如果库的源码本身就是由 ts 写的,那么在使用
tsc
脚本将 ts 编译为 js 的时候,添加declaration
选项,就可以同时也生成.d.ts
声明文件了.我们可以在命令行中添加
--declaration
(简写-d
),或者在tsconfig.json
中添加declaration
选项.这里以
tsconfig.json
为例:上例中我们添加了 outDir 选项,将 ts 文件的编译结果输出到 lib 目录下,然后添加了 declaration 选项,设置为 true,表示将会由 ts 文件自动生成 .d.ts 声明文件,也会输出到 lib 目录下.
发布声明文件
我们为一个开源库编写了声明文件后应该如何发布?
目前有两个选择:
第一方声明
如果是手动写的声明文件,那么需要满足以下条件之一,才能被正确的识别:
package.json
中的types
或typings
字段指定一个类型声明文件地址index.d.ts
文件package.json
中的main
字段指定的入口文件),编写一个同名不同后缀的.d.ts
文件第一种方式是给
package.json
中的types
或typings
字段指定一个类型声明文件地址。比如:指定了
types
为foo.d.ts
之后,导入此库的时候,就会去找foo.d.ts
作为此库的类型声明文件了。typings
与types
一样,只是另一种写法。如果没有指定
types
或typings
,那么就会在根目录下寻找index.d.ts
文件,将它视为此库的类型声明文件。如果没有找到
index.d.ts
文件,那么就会寻找入口文件(package.json
中的main
字段指定的入口文件)是否存在对应同名不同后缀的.d.ts
文件。比如
package.json
是这样时:就会先识别
package.json
中是否存在types
或typings
字段。发现不存在,那么就会寻找是否存在index.d.ts
文件。如果还是不存在,那么就会寻找是否存在lib/index.d.ts
文件。假如说连lib/index.d.ts
都不存在的话,就会被认为是一个没有提供类型声明文件的库了。有的库为了支持导入子模块,比如
import bar from 'foo/lib/bar'
,就需要额外再编写一个类型声明文件lib/bar.d.ts
或者lib/bar/index.d.ts
,这与自动生成声明文件类似,一个库中同时包含了多个类型声明文件。将声明文件发布到DefinitelyTyped
如果我们是在给别人的仓库添加类型声明文件,但原作者不愿意合并 pull request,那么就需要将声明文件发布到
@types
下。与普通的 npm 模块不同,
@types
是统一由 DefinitelyTyped 管理的。要将声明文件发布到@types
下,就需要给 DefinitelyTyped 创建一个 pull-request,其中包含了类型声明文件,测试代码,以及tsconfig.json
等。pull-request 需要符合它们的规范,并且通过测试,才能被合并,稍后就会被自动发布到
@types
下。在 DefinitelyTyped 中创建一个新的类型声明,需要用到一些工具,DefinitelyTyped 的文档中已经有了详细的介绍,这里就不赘述了,以官方文档为准。
小结
本节我们学习了声明文件基本的编写技巧,接下来我们需要进行一次实战,为一个纯 JavaScript 编写的开源库编写 d.ts.
The text was updated successfully, but these errors were encountered: