@@ -78,7 +78,6 @@ jQuery('#foo');
7878
7979``` plain
8080/path/to/project
81- ├── README.md
8281├── src
8382| ├── index.ts
8483| └── jQuery.d.ts
@@ -111,12 +110,12 @@ npm install @types/jquery --save-dev
111110
112111库的使用场景主要有以下几种:
113112
114- - 全局变量:通过 ` <script> ` 标签引入第三方库,注入全局变量
115- - npm 包:通过 ` import foo from 'foo' ` 导入,符合 ES6 模块规范
116- - UMD 库:既可以通过 ` <script> ` 标签引入,又可以通过 ` import ` 导入
117- - 直接扩展全局变量:通过 ` <script> ` 标签引入后,改变一个全局变量的结构
118- - 在 npm 包或 UMD 库中扩展全局变量:引用 npm 包或 UMD 库后,改变一个全局变量的结构
119- - 模块插件:通过 ` <script> ` 或 ` import ` 导入后,改变另一个模块的结构
113+ - [ 全局变量] ( #quan-ju-bian-liang ) :通过 ` <script> ` 标签引入第三方库,注入全局变量
114+ - [ npm 包] ( #npm-bao ) :通过 ` import foo from 'foo' ` 导入,符合 ES6 模块规范
115+ - [ UMD 库] ( #umd-ku ) :既可以通过 ` <script> ` 标签引入,又可以通过 ` import ` 导入
116+ - [ 直接扩展全局变量] ( #zhi-jie-kuo-zhan-quan-ju-bian-liang ) :通过 ` <script> ` 标签引入后,改变一个全局变量的结构
117+ - [ 在 npm 包或 UMD 库中扩展全局变量] ( #zai-npm-bao-huo-umd-ku-zhong-kuo-zhan-quan-ju-bian-liang ) :引用 npm 包或 UMD 库后,改变一个全局变量的结构
118+ - [ 模块插件] ( #mo-kuai-cha-jian ) :通过 ` <script> ` 或 ` import ` 导入后,改变另一个模块的结构
120119
121120### 全局变量
122121
@@ -126,7 +125,6 @@ npm install @types/jquery --save-dev
126125
127126``` plain
128127/path/to/project
129- ├── README.md
130128├── src
131129| ├── index.ts
132130| └── jQuery.d.ts
@@ -137,12 +135,12 @@ npm install @types/jquery --save-dev
137135
138136全局变量的声明文件主要有以下几种语法:
139137
140- - ` declare var ` 声明全局变量
141- - ` declare function ` 声明全局方法
142- - ` declare class ` 声明全局类
143- - ` declare enum ` 声明全局枚举类型
144- - ` declare namespace ` 声明(含有子属性的)全局对象
145- - ` interface ` 和 ` type ` 声明全局类型
138+ - [ ` declare var ` ] ( #declare-var ) 声明全局变量
139+ - [ ` declare function ` ] ( #declare-function ) 声明全局方法
140+ - [ ` declare class ` ] ( #declare-class ) 声明全局类
141+ - [ ` declare enum ` ] ( #declare-enum ) 声明全局枚举类型
142+ - [ ` declare namespace ` ] ( #declare-namespace ) 声明(含有子属性的)全局对象
143+ - [ ` interface ` 和 ` type ` ] ( #interface-he-type ) 声明全局类型
146144
147145#### ` declare var `
148146
@@ -494,7 +492,6 @@ jQuery.ajax('/api/get_something');
494492
495493``` plain
496494/path/to/project
497- ├── README.md
498495├── src
499496| └── index.ts
500497├── types
@@ -521,14 +518,14 @@ jQuery.ajax('/api/get_something');
521518
522519注意 ` module ` 配置可以有很多种选项,不同的选项会影响模块的导入导出模式。这里我们使用了 ` commonjs ` 这个最常用的选项,后面的教程也都默认使用的这个选项。
523520
524- 不管采用了以上两种方式中的哪一种,我都* 强烈建议* 大家将书写好的声明文件(通过给原作者发 pull request,或者直接提交到 ` @types ` 里)发布到开源社区中,享受了这么多社区的优秀的资源,就应该在力所能及的时候给出一些回馈。只有所有人都参与进来,才能让 ts 社区更加繁荣。
521+ 不管采用了以上两种方式中的哪一种,我都** 强烈建议** 大家将书写好的声明文件(通过给第三发库发 pull request,或者直接提交到 ` @types ` 里)发布到开源社区中,享受了这么多社区的优秀的资源,就应该在力所能及的时候给出一些回馈。只有所有人都参与进来,才能让 ts 社区更加繁荣。
525522
526523npm 包的声明文件主要有以下几种语法:
527524
528- - ` export ` 导出变量
529- - ` export namespace ` 导出(含有子属性的)全局对象
530- - ` export default ` ES6 默认导出
531- - ` export = ` commonjs 导出模块
525+ - [ ` export ` ] ( #export ) 导出变量
526+ - [ ` export namespace ` ] ( #export-namespace ) 导出(含有子属性的)对象
527+ - [ ` export default ` ] ( #export-default ) ES6 默认导出
528+ - [ ` export = ` ] ( #export-1 ) commonjs 导出模块
532529
533530#### ` export `
534531
@@ -999,21 +996,163 @@ export = jQuery;
999996
1000997除了这两种三斜线指令之外,还有其他的三斜线指令,比如 ` /// <reference no-default-lib="true"/> ` , ` /// <amd-module /> ` 等,但它们都是废弃的语法,故这里就不介绍了,详情可见[ 官网] ( http://www.typescriptlang.org/docs/handbook/triple-slash-directives.html ) 。
1001998
1002- ### 最佳实践
999+ ### 自动生成声明文件
1000+
1001+ 如果库的源码本身就是由 ts 写的,那么在使用 ` tsc ` 脚本将 ts 编译为 js 的时候,添加 ` declaration ` 选项,就可以同时也生成 ` .d.ts ` 声明文件了。
1002+
1003+ 我们可以在命令行中添加 ` --declaration ` (简写 ` -d ` ),或者在 ` tsconfig.json ` 中添加 ` declaration ` 选项。这里以 ` tsconfig.json ` 为例:
1004+
1005+ ``` json
1006+ {
1007+ "compilerOptions" : {
1008+ "module" : " commonjs" ,
1009+ "outDir" : " lib" ,
1010+ "declaration" : true ,
1011+ }
1012+ }
1013+ ```
1014+
1015+ 上例中我们添加了 ` outDir ` 选项,将 ts 文件的编译结果输出到 ` lib ` 目录下,然后添加了 ` declaration ` 选项,设置为 ` true ` ,表示将会由 ts 文件自动生成 ` .d.ts ` 声明文件,也会输出到 ` lib ` 目录下。
1016+
1017+ 运行 ` tsc ` 之后,目录结构如下[ <sup >30</sup >] ( https://github.com/xcatliu/typescript-tutorial/tree/master/examples/declaration-files/30-auto-d-ts ) :
10031018
1004- TODO
1019+ ``` plain
1020+ /path/to/project
1021+ ├── lib
1022+ | ├── bar
1023+ | | ├── index.d.ts
1024+ | | └── index.js
1025+ | ├── index.d.ts
1026+ | └── index.js
1027+ ├── src
1028+ | ├── bar
1029+ | | └── index.ts
1030+ | └── index.ts
1031+ ├── package.json
1032+ └── tsconfig.json
1033+ ```
1034+
1035+ 在这个例子中,` src ` 目录下有两个 ts 文件,分别是 ` src/index.ts ` 和 ` src/bar/index.ts ` ,它们被编译到 ` lib ` 目录下的同时,也会生成对应的两个声明文件 ` lib/index.d.ts ` 和 ` lib/bar/index.d.ts ` 。它们的内容分别是:
1036+
1037+ ``` ts
1038+ // src/index.ts
1039+
1040+ export * from ' ./bar' ;
10051041
1006- ### 发布声明文件
1042+ export default function foo() {
1043+ return ' foo' ;
1044+ }
1045+ ```
1046+
1047+ ``` ts
1048+ // src/bar/index.ts
10071049
1008- TODO
1050+ export function bar() {
1051+ return ' bar' ;
1052+ }
1053+ ```
1054+
1055+ ``` ts
1056+ // lib/index.d.ts
1057+
1058+ export * from ' ./bar' ;
1059+ export default function foo(): string ;
1060+ ```
1061+
1062+ ``` ts
1063+ // lib/bar/index.d.ts
1064+
1065+ export declare function bar(): string ;
1066+ ```
1067+
1068+ 可见,自动生成的声明文件基本保持了源码的结构,而将具体实现去掉了,生成了对应的类型声明。
1069+
1070+ 使用 ` tsc ` 自动生成声明文件时,每个 ts 文件都会对应一个 ` .d.ts ` 声明文件。这样的好处是,使用方不仅可以在使用 ` import foo from 'foo' ` 导入默认的模块时获得类型提示,还可以在使用 ` import bar from 'foo/lib/bar' ` 导入一个子模块时,也获得对应的类型提示。
1071+
1072+ 除了 ` declaration ` 选项之外,还有几个选项也与自动生成声明文件有关,这里只简单列举出来,不做详细演示了:
1073+
1074+ - ` declarationDir ` 设置生成 ` .d.ts ` 文件的目录
1075+ - ` declarationMap ` 对每个 ` .d.ts ` 文件,都生成对应的 ` .d.ts.map ` (sourcemap)文件
1076+ - ` emitDeclarationOnly ` 仅生成 ` .d.ts ` 文件,不生成 ` .js ` 文件
1077+
1078+ ## 发布声明文件
1079+
1080+ 当我们为一个库写好了声明文件之后,下一步就是将它发布出去了。
1081+
1082+ 此时有两种方案:
1083+
1084+ 1 . 将声明文件和源码放在一个仓库中
1085+ 2 . 将声明文件发布到 ` @types ` 下
1086+
1087+ 这两种方案中优先选择第一种方案。保持声明文件与源码在一个仓库中,使用时就不需要额外增加单独的声明文件库的依赖了,而且也能保证声明文件的版本与源码的版本保持一致。
1088+
1089+ 仅当我们在给别人的仓库添加类型声明文件,但原作者不愿意合并 pull request 时,才需要使用第二种方案,将声明文件发布到 ` @types ` 下。
1090+
1091+ ### 将声明文件和源码放在一个仓库中
1092+
1093+ 如果声明文件是通过 ` tsc ` 自动生成的,那么无需做任何其他配置,只需要把编译好的文件也发布到 npm 上,使用方就可以获取到类型提示了。
1094+
1095+ 如果是手动写的声明文件,那么需要满足以下条件之一,才能被正确的识别:
1096+
1097+ - 给 ` package.json ` 中的 ` types ` 或 ` typings ` 字段指定一个类型声明文件地址
1098+ - 在项目根目录下,编写一个 ` index.d.ts ` 文件
1099+ - 针对入口文件(` package.json ` 中的 ` main ` 字段指定的入口文件),编写一个同名不同后缀的 ` .d.ts ` 文件
1100+
1101+ 第一种方式是给 ` package.json ` 中的 ` types ` 或 ` typings ` 字段指定一个类型声明文件地址。比如:
1102+
1103+ ``` json
1104+ {
1105+ "name" : " foo" ,
1106+ "version" : " 1.0.0" ,
1107+ "main" : " lib/index.js" ,
1108+ "types" : " foo.d.ts" ,
1109+ }
1110+ ```
1111+
1112+ 指定了 ` types ` 为 ` foo.d.ts ` 之后,导入此库的时候,就会去找 ` foo.d.ts ` 作为此库的类型声明文件了。
1113+
1114+ ` typings ` 与 ` types ` 一样,只是另一种写法。
1115+
1116+ 如果没有指定 ` types ` 或 ` typings ` ,那么就会在根目录下寻找 ` index.d.ts ` 文件,将它视为此库的类型声明文件。
1117+
1118+ 如果没有找到 ` index.d.ts ` 文件,那么就会寻找入口文件(` package.json ` 中的 ` main ` 字段指定的入口文件)是否存在对应同名不同后缀的 ` .d.ts ` 文件。
1119+
1120+ 比如 ` package.json ` 是这样时:
1121+
1122+ ``` json
1123+ {
1124+ "name" : " foo" ,
1125+ "version" : " 1.0.0" ,
1126+ "main" : " lib/index.js"
1127+ }
1128+ ```
1129+
1130+ 就会先识别 ` package.json ` 中是否存在 ` types ` 或 ` typings ` 字段。发现不存在,那么就会寻找是否存在 ` index.d.ts ` 文件。如果还是不存在,那么就会寻找是否存在 ` lib/index.d.ts ` 文件。假如说连 ` lib/index.d.ts ` 都不存在的话,就会被认为是一个没有提供类型声明文件的库了。
1131+
1132+ 有的库为了支持导入子模块,比如 ` import bar from 'foo/lib/bar' ` ,就需要额外再编写一个类型声明文件 ` lib/bar.d.ts ` 或者 ` lib/bar/index.d.ts ` ,这与自动生成声明文件类似,一个库中同时包含了多个类型声明文件。
1133+
1134+ ### 将声明文件发布到 ` @types ` 下
1135+
1136+ 如果我们是在给别人的仓库添加类型声明文件,但原作者不愿意合并 pull request,那么就需要将声明文件发布到 ` @types ` 下。
1137+
1138+ 与普通的 npm 模块不同,` @types ` 是统一由 [ DefinitelyTyped] [ ] 管理的。要将声明文件发布到 ` @types ` 下,就需要给 [ DefinitelyTyped] [ ] 创建一个 pull-request,其中包含了类型声明文件,测试代码,以及 ` tsconfig.json ` 等。
1139+
1140+ pull-request 需要符合它们的规范,并且通过测试,才能被合并,稍后就会被自动发布到 ` @types ` 下。
1141+
1142+ 在 [ DefinitelyTyped] [ ] 中创建一个新的类型声明,需要用到一些工具,[ DefinitelyTyped] [ ] 的文档中已经有了[ 详细的介绍] ( https://github.com/DefinitelyTyped/DefinitelyTyped#create-a-new-package ) ,这里就不赘述了,以官方文档为准。
1143+
1144+ 如果大家有此类需求,可以参考下笔者[ 提交的 pull-request] ( https://github.com/DefinitelyTyped/DefinitelyTyped/pull/30336/files ) 。
10091145
10101146## 参考
10111147
10121148- [ Writing Declaration Files] ( http://www.typescriptlang.org/docs/handbook/writing-declaration-files.html ) ([ 中文版] ( https://zhongsp.gitbooks.io/typescript-handbook/content/doc/handbook/declaration%20files/Introduction.html ) )
10131149- [ Triple-Slash Directives] ( http://www.typescriptlang.org/docs/handbook/triple-slash-directives.html ) ([ 中文版] ( https://zhongsp.gitbooks.io/typescript-handbook/content/doc/handbook/Triple-Slash%20Directives.html ) )
10141150- [ typeRoots or paths] ( https://github.com/Microsoft/TypeScript/issues/22217#issuecomment-369783776 )
1151+ - [ DefinitelyTyped] [ ]
10151152
10161153---
10171154
10181155- [ 上一章:类型断言] ( type-assertion.md )
10191156- [ 下一章:内置对象] ( built-in-objects.md )
1157+
1158+ [ DefinitelyTyped ] : https://github.com/DefinitelyTyped/DefinitelyTyped/
0 commit comments