主题
TS 类型声明文件
1. 什么是声明文件
以.d.ts
结尾的文件
2. 声明文件有什么作用
为 JS 代码提供类型声明
3. 声明文件的位置
- 放置到
tsconfig.json
配置中include
字段包含的目录或者子目录的任何位置都会生效 - 放置到
node_modules/@types
文件夹中(一般手动安装的类型申明文件) - 手动配置
tsconfig.json
中的typesRoot
字段,值为数组,配置了此字段,可以指定多个目录,其余地方的类型申明文件会失效,包括node_modules/@types
下的也会失效(高优先级) - 与 js 代码所在目录相同,并且名字也相同的文件。(用 ts 编写的工程发布之后的格式一般都长这样)
4. 编写声明文件
4.1 自动生成
- 场景:你的工程是 ts 开发的,发布(编译)之后,是 js 文件,发布的是 js 文件,若发布的文件需要其他开者使用,可以使用类型声明文件来描述发布结果中的类型
配置方式: 在tsconfig.config
的 declaration:true
即可,在打包时候,就会在生成 js 时候同时生成一个同名的.d.ts
声明文件
配置sourceMap:true
会在生成同名的.js.map
源码地图文件
4.2 手动编写
- 场景
- 对已有一个用 js 编写的库,并且改动该库为 ts 成本较高,可以手动编写声明文件
- 对一些第三方库,他们使用 js 编写,并且他没有提供声明文件,我们可以自己手动编写声明文件(现在一般安装的库都会有声明文件)
编写细节
- 文件名无关,只要后缀为
.d.ts
即可
全局声明
用于声明一些全局对象、属性、变量等
声明用declare
关键字进行声明
提示
declare
关键字用来告诉编译器,某个类型是存在的,可以在当前文件中使用。
它的主要作用,就是让当前文件可以使用其他文件声明的类型。举例来说,自己的脚本使用外部库定义的函数,编译器会因为不知道外部函数的类型定义而报错,这时就可以在自己的脚本里面使用 declare 关键字,告诉编译器外部函数的类型。这样的话,编译单个脚本就不会因为使用了外部类型而报错。
例如:
ts
// 声明一个nodejs中的console
interface Console {
log: (message?: string) => void;
error: (message?: string) => void;
}
declare var console: Console;
// 或者 通过命名空间
declare namespace console {
function log(message: string): void;
function error(message: string): void;
}
类型声明文件时写给 ts 编译器看的,不影响运行
类型声明文件只能声明类型,申明类型时候不能赋值
namespace
:表示命名空间,可以将其认定为是一个对象,明明 空间中的内容,必须通过命名空间.成员名
访问 如果想把变量、函数、类组织在一起,可以将 declare 与 module 或 namespace 一起使用。
模块声明
语法
typescript
declare module "moduleA" {
export interface Url {
protocol?: string;
hostname?: string;
pathname?: string;
}
}
提示
declare module
和 declare namespace
里面,加不加 export
关键字都可以。
5. 一些常见的declare
语法
declare 关键字可以描述以下类型。
- 变量(const、let、var 命令声明)
- type 或者 interface 命令声明的类型
- class
- enum
- 函数(function)
- 模块(module)
- 命名空间(namespace)
declare class 示例
typescript
declare class Animal {
constructor(name: string);
eat(): void;
sleep(): void;
}
declare module,declare namespace 示例
typescript
declare namespace AnimalLib {
class Animal {
constructor(name: string);
eat(): void;
sleep(): void;
}
type Animals = "Fish" | "Dog";
}
// 或者
declare module AnimalLib {
class Animal {
constructor(name: string);
eat(): void;
sleep(): void;
}
type Animals = "Fish" | "Dog";
}
declare global 示例
如果要为 JavaScript 引擎的原生对象添加属性和方法,可以使用 declare global {}语法。
typescript
export {};
declare global {
interface String {
toSmallString(): string;
}
}
String.prototype.toSmallString = (): string => {
// 具体实现
return "";
};
上面示例中,为 JavaScript 原生的 String 对象添加了 toSmallString()方法。declare global 给出这个新增方法的类型描述。
这个示例第一行的空导出语句 export {},作用是强制编译器将这个脚本当作模块处理。这是因为 declare global 必须用在模块里面。
下面的示例是为 window 对象添加一个属性 myAppConfig。
typescript
export {};
declare global {
interface window {
myAppConfig: object;
}
}
const config = window.myAppConfig;
declare global 只能扩充现有对象的类型描述,不能增加新的顶层类型。
declare enum 示例
declare 关键字给出 enum 类型描述的例子如下,下面的写法都是允许的。
typescript
declare enum E1 {
A,
B,
}
declare enum E2 {
A = 0,
B = 1,
}
declare const enum E3 {
A,
B,
}
declare const enum E4 {
A = 0,
B = 1,
}
declare module 用于类型声明文件
我们可以为每个模块脚本,定义一个.d.ts 文件,把该脚本用到的类型定义都放在这个文件里面。但是,更方便的做法是为整个项目,定义一个大的.d.ts 文件,在这个文件里面使用 declare module 定义每个模块脚本的类型。
下面的示例是 node.d.ts 文件的一部分。
typescript
declare module "url" {
export interface Url {
protocol?: string;
hostname?: string;
pathname?: string;
}
export function parse(
urlStr: string,
parseQueryString?,
slashesDenoteHost?
): Url;
}
declare module "path" {
export function normalize(p: string): string;
export function join(...paths: any[]): string;
export var sep: string;
}
上面示例中,url 和 path 都是单独的模块脚本,但是它们的类型都定义在 node.d.ts 这个文件里面。
使用时,自己的脚本使用三斜杠命令,加载这个类型声明文件。
typescript
/// <reference path="node.d.ts"/>
如果没有上面这一行命令,自己的脚本使用外部模块时,就需要在脚本里面使用 declare 命令单独给出外部模块的类型。