15. declare 关键字与d.ts
declare
declare 是 TypeScript 中的关键字,用于声明变量、函数、类、模块或类型的存在,但不做具体实现。它的作用是告诉 TypeScript 编译器:“这个东西已经存在了,在别的地方定义了,你就不要再报错了”。
declare 关键字用来告诉编译器,某个类型是存在的,可以在当前文件中使用。
它的主要作用,就是让当前文件可以使用其他文件声明的类型。举例来说,自己的脚本使用外部库定义的函数,编译器会因为不知道外部函数的类型定义而报错,这时就可以在自己的脚本里面使用declare关键字,告诉编译器外部函数的类型。这样的话,编译单个脚本就不会因为使用了外部类型而报错。
declare 关键字可以描述以下类型。
- 变量(const、let、var 命令声明)
- type 或者 interface 命令声明的类型
- class
- enum
- 函数(function)
- 模块(module)
- 命名空间(namespace)
declare 关键字的重要特点是,它只是通知编译器某个类型是存在的,不用给出具体实现。比如,只描述函数的类型,不给出函数的实现,如果不使用declare,这是做不到的。
declare 只能用来描述已经存在的变量和数据结构,不能用来声明新的变量和数据结构。另外,所有 declare 语句都不会出现在编译后的文件里面。
d.ts
单独使用的模块,一般会同时提供一个单独的类型声明文件(declaration file),把本模块的外部接口的所有类型都写在这个文件里面,便于模块使用者了解接口,也便于编译器检查使用者的用法是否正确。
类型声明文件里面只有类型代码,没有具体的代码实现。它的文件名一般为[模块名].d.ts的形式,其中的d表示 declaration(声明)。
举例来说,有一个模块的代码如下。
const maxInterval = 12;
function getArrayLength(arr) {
return arr.length;
}
module.exports = {
getArrayLength,
maxInterval,
};
它的类型声明文件可以写成下面这样。
export function getArrayLength(arr: any[]): number;
export const maxInterval: 12;
下面是一个如何使用类型声明文件的简单例子。有一个类型声明文件types.d.ts。
// types.d.ts
export interface Character {
catchphrase?: string;
name: string;
}
然后,就可以在 TypeScript 脚本里面导入该文件声明的类型。
// index.ts
import { Character } from "./types";
export const character:Character = {
catchphrase: "Yee-haw!",
name: "Sandy Cheeks",
};
类型声明文件也可以包括在项目的 tsconfig.json 文件里面,这样的话,编译器打包项目时,会自动将类型声明文件加入编译,而不必在每个脚本里面加载类型声明文件。比如,moment 模块的类型声明文件是moment.d.ts,使用 moment 模块的项目可以将其加入项目的 tsconfig.json 文件。
{
"compilerOptions": {},
"files": [
"src/index.ts",
"typings/moment.d.ts"
]
}
类型声明文件主要有以下三种来源。
- TypeScript 编译器自动生成。
只要使用编译选项declaration,编译器就会在编译时自动生成单独的类型声明文件。
下面是在tsconfig.json文件里面,打开这个选项。
{
"compilerOptions": {
"declaration": true
}
}
- TypeScript 内置类型文件。
安装 TypeScript 语言时,会同时安装一些内置的类型声明文件,主要是内置的全局对象(JavaScript 语言接口和运行环境 API)的类型声明。
这些内置声明文件位于 TypeScript 语言安装目录的lib文件夹内,数量大概有几十个
- 外部模块的类型声明文件,需要自己安装。
如果项目中使用了外部的某个第三方代码库,那么就需要这个库的类型声明文件。
这时又分成三种情况。
(1)这个库自带了类型声明文件。
(2)这个库没有自带,但是可以找到社区制作的类型声明文件。
(3)找不到类型声明文件,需要自己写
总结
类型声明文件只包含类型描述,不包含具体实现,所以非常适合使用 declare 语句来描述类型。
类型声明文件里面,变量的类型描述必须使用declare命令,否则会报错,因为变量声明语句是值相关代码。
declare let foo:string;
interface 类型有没有declare都可以,因为 interface 是完全的类型代码。
interface Foo {} // 正确
declare interface Foo {} // 正确
三斜杠命令
如果类型声明文件的内容非常多,可以拆分成多个文件,然后入口文件使用三斜杠命令,加载其他拆分后的文件。
举例来说,入口文件是main.d.ts,里面的接口定义在interfaces.d.ts,函数定义在functions.d.ts。那么,main.d.ts里面可以用三斜杠命令,加载后面两个文件。
/// <reference path="./interfaces.d.ts" />
/// <reference path="./functions.d.ts" />
三斜杠命令(///)是一个 TypeScript 编译器命令,用来指定编译器行为。它只能用在文件的头部,如果用在其他地方,会被当作普通的注释。另外,若一个文件中使用了三斜线命令,那么在三斜线命令之前只允许使用单行注释、多行注释和其他三斜线命令,否则三斜杠命令也会被当作普通的注释。
- **/// **是最常见的三斜杠命令,告诉编译器在编译时需要包括的文件,常用来声明当前脚本依赖的类型文件
- /// types 参数用来告诉编译器当前脚本依赖某个 DefinitelyTyped 类型库,通常安装在node_modules/@types目录。
- **/// **命令允许脚本文件显式包含内置 lib 库,等同于在tsconfig.json文件里面使用lib属性指定 lib 库。
评论