打算为你的团队写一个封装好的工具?TS的声明文件是必不可少的,它不仅仅让你的工具支持TS,更是负责充当一个说明书的作用,让人对其的使用一目了然。
什么是声明语句?什么时候需要他?
假如我们想使用第三方库 jQuery,一种常见的方式是在 html 中通过script 标签引入 jQuery,然后就可以使用全局变量 $ 或 jQuery 了。
我们通常这样获取一个 id 是 foo 的元素:
$('#foo');
// or
jQuery('#foo');
// ts并不了解这两个变量从何来,到哪去。我们可以告诉ts的编译器,这个东西大概是什么
// 其用于编译时的检查,在编译结果中会被删除
declare var jQuery: (selector: string) => any;
jQuery('#foo');
复制代码
这就是声明语句。如果你是js编写的,往往需要一个声明文件。
如果你是ts编写的,那么让ts自动生成就好了。
以下教程根据js的库进行编写声明文件。
什么是声明文件?
你可以把声明语句看作是声明文件的“组件”。声明语句组成声明文件。
通常我们会把声明语句放到一个单独的文件{(jQuery.d.ts)声明文件必需以 .d.ts 为后缀。}中,这就是声明文件
// src/jQuery.d.ts
declare var jQuery: (selector: string) => any;
复制代码
一般来说,ts 会解析项目中所有的 *.ts 文件, .d.ts 的文件也属于*.ts文件。
所以当我们将 jQuery.d.ts 放到项目中时,其他所有 *.ts 文件就都可以获得 jQuery 的类型定义了。
假如仍然无法解析,那么可以检查下 tsconfig.json 。
这里只演示了全局变量模式的声明文件,通过模块导入的方式的话,那么引入声明文件又是另一种方式了。
书写声明文件!
一般来说第三方库都会提供声明文件,我们只需要安装它就好了。
但有一些库不会提供声明文件,我们就需要自己书写声明文件了。
前面只介绍了最简单的声明文件内容,而真正书写一个声明文件并不是一件简单的事
书写声明文件有多种场景需要契合,例如npm导入和script导入的声明文件的写法与使用方法都不一样,我们这也知会讨论比较常用的这两种方式,如果看官有兴趣,可以自行移步教程学习。
1. 全局变量:通过 script 标签引入第三方库,注入全局变量
全局变量是最简单的一种场景,之前举的例子就是通过 script 标签引入 jQuery,注入全局变量 $ 和 jQuery。
使用全局变量的声明文件时,如果是以 npm install @types/xxx --save-dev 安装的,则不需要任何配置。
如果是将声明文件直接存放于当前项目中,则建议和其他源码一起放到 src 目录下(或者对应的源码目录下):
/path/to/project
├── src
| ├── index.ts
| └── jQuery.d.ts
└── tsconfig.json
复制代码
如果没有生效,可以检查下 tsconfig.json 中的 files、include 和 exclude 配置,确保其包含了 jQuery.d.ts 文件。
全局变量的声明文件主要有以下几种语法:
1. declare var / let / const声明全局变量
没什么区别 const定义的无法修改。
```
//使用const的时候是最多的,一般不允许他人修改你的函数
declare const jQuery: (selector: string) => any;
```
复制代码
2. declare function 声明全局方法
```
declare function jQuery(selector: string): any;
```
复制代码
3. declare class 声明全局类
```
declare class Animal {
name: string;
constructor(name: string);
sayHi(): string;
}
//其他文件中
let cat = new Animal('Tom');
```
复制代码
4. declare enum 声明全局枚举类型
不讨论,这个需要后面的知识
复制代码
5. declare namespace 声明(含有子属性的)全局对象
declare namespace 还是比较常用的,它用来表示全局变量是一个对象,包含很多子属性。
举个例子:
//jQuery 是一个全局变量,它是一个对象
//jQuery.ajax 方法可以调用
//那么我们就应该使用 declare namespace jQuery 来声明这个属性的全局变量。
declare namespace jQuery {
function ajax(url: string, settings?: any): void;
}
//更为复杂一点的例子
declare namespace jQuery {
function ajax(url: string, settings?: any): void;
const version: number;
class Event {
blur(eventType: EventType): void
}
enum EventType {
CustomClick
}
}
复制代码
当然嵌套也是经常看到的事情,我们也可以使用namespace嵌套使用
declare namespace jQuery {
function ajax(url: string, settings?: any): void;
namespace fn {
function extend(object: any): void;
}
}
复制代码
6. interface 和 type 声明全局类型
除了主要的全局变量之外,可能有一些类型我们也希望能暴露出来。
在类型声明文件中,我们可以直接使用 interface 或 type 来声明一个全局的接口或类型:
// src/jQuery.d.ts
interface AjaxSettings {
method?: 'GET' | 'POST'
data?: any;
}
declare namespace jQuery {
function ajax(url: string, settings?: AjaxSettings): void;
}
复制代码
2. npm 包:通过 import foo from 'foo' 导入,符合 ES6 模块规范
在我们给一个 npm 包创建声明文件之前,需要先看看它的声明文件是否已经存在。一般来说,npm 包的声明文件可能存在于两个地方:
与该 npm 包在一起。package.json中有types字段,或有一个index.d.ts声明文件。这种模式不需要额外安装其他包,是最为推荐的,所以以后我们自己创建 npm 包的时候,最好也将声明文件与 npm 包绑定在一起。
发布到 @types 里。我们只需要尝试安装一下对应的 @types 包就知道是否存在该声明文件,安装命令是 npm install @types/foo --save-dev。这种模式一般是由于 npm 包的维护者没有提供声明文件,所以只能由其他人将声明文件发布到 @types 里了。
假如以上两种方式都没有找到对应的声明文件,那么我们就需要自己为它写声明文件了。
由于是通过 import 语句导入的模块,所以声明文件存放的位置也有所约束,一般有两种方案:
创建一个 node_modules/@types/foo/index.d.ts 文件,存放 foo 模块的声明文件。这种方式不需要额外的配置,但是 node_modules 目录不稳定,代码也没有被保存到仓库中,无法回溯版本,有不小心被删除的风险,故不太建议用这种方案,一般只用作临时测试。
创建一个 types 目录,专门用来管理自己写的声明文件,将 foo 的声明文件放到 types/foo/index.d.ts 中。这种方式需要配置下 tsconfig.json 中的 paths 和 baseUrl 字段。
介绍一下第二种方案
├── src
| └── index.ts
├── types
| └── foo
| └── index.d.ts
└── tsconfig.json
//tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"baseUrl": "./",
"paths": {
"*": ["types/*"]
}
}
}
复制代码
npm 包的声明文件主要有以下几种语法:
1. export 导出变量
在 npm 包的声明文件中,使用 declare 不再会声明一个全局变量,而只会在当前文件中声明一个局部变量。
只有在声明文件中使用 export 导出,然后在使用方 import 导入后,才会应用到这些类型声明。
export namespace 导出(含有子属性的)对象
// 某声明文件
export const name: string;
export function getName(): string;
export class Animal {
constructor(name: string);
sayHi(): string;
}
export enum Directions {
Up,
Down,
Left,
Right
}
export interface Options {
data: any;
}
// 某使用文件
import { name, getName, Animal, Directions, Options } from 'foo';
console.log(name);
let myName = getName();
let cat = new Animal('Tom');
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
let options: Options = {
data: {
name: 'foo'
}
};
复制代码export default ES6 默认导出
export = commonjs 导出模块
。。。烂尾,感觉没啥好写的,很好理解
内容从此处摘抄
https://ts.xcatliu.com/basics/declaration-files.html#%E4%B9%A6%E5%86%99%E5%A3%B0%E6%98%8E%E6%96%87%E4%BB%B6
复制代码