TypeScript 声明文件
TypeScript 的一个核心优势是它能够与现有的 JavaScript 库和代码无缝协作。然而,标准的 JavaScript 文件(.js)本身不包含类型信息。为了让 TypeScript 编译器理解这些 JavaScript 库的类型、函数签名和对象形状,我们使用声明文件(Declaration Files)。
声明文件以 .d.ts 为扩展名,它们不包含任何实现代码(函数体、变量的初始值等),只包含类型定义。
为什么需要声明文件?
当你使用一个流行的 JavaScript 库(如 jQuery, Lodash, React)时,你希望在 TypeScript 代码中调用它提供的函数时,能获得类型检查和智能自动补全。声明文件就是提供这些类型信息的桥梁。
没有声明文件的情况:
// 假设我们在使用一个没有声明文件的 'my-library'
import { doSomething } from 'my-library';
// TypeScript 编译器会报错,因为它不知道 'my-library' 是什么,
// 也不知道 doSomething 函数的存在和它的参数类型。
// Error: Cannot find module 'my-library'.
doSomething(123);有声明文件的情况:
// my-library.d.ts (声明文件)
declare module 'my-library' {
export function doSomething(value: number): string;
}// app.ts (你的代码)
import { doSomething } from 'my-library';
doSomething(123); // OK
// doSomething("hello"); // Error: Argument of type 'string' is not assignable to parameter of type 'number'.如何获取声明文件?
对于绝大多数流行的 JavaScript 库,你不需要手动编写声明文件。社区已经为我们做好了这项工作。
1. 库自带声明文件
许多现代的库在发布时就已经包含了它们自己的 .d.ts 声明文件。当你通过 npm 安装这些库时,声明文件会自动被 TypeScript 识别。
2. DefinitelyTyped 项目
对于那些本身不包含类型声明的 JavaScript 库,有一个名为 DefinitelyTyped 的庞大社区项目,它为成千上万的库提供了高质量的声明文件。
这些声明文件都发布在 npm 的 @types scope 下。你只需要安装对应的 @types 包即可。
例如,要为 lodash 库安装声明文件,你只需运行:
npm install --save-dev @types/lodash安装完成后,你就可以在 TypeScript 项目中像使用原生 TypeScript 库一样使用 lodash 了。
编写你自己的声明文件
在某些情况下,你可能需要为你自己的 JavaScript 代码或一个没有类型定义的第三方库编写声明文件。
declare 关键字
declare 关键字用于告诉 TypeScript 某个变量、函数或模块是存在的,并且有特定的类型,但它的具体实现是在其他地方(通常是一个 .js 文件)。
声明一个全局变量:
// global.d.ts
declare const MY_GLOBAL_VARIABLE: string;声明一个模块:
// my-untyped-module.d.ts
declare module 'my-untyped-module' {
export function someFunction(arg: string): boolean;
export const someConstant: number;
}声明文件结构
- 全局声明: 如果你的 JavaScript 代码是在全局作用域中运行(例如通过
<script>标签引入),你可以直接在.d.ts文件中使用declare var,declare function等。 - 模块化声明: 如果你的 JavaScript 代码是一个模块,你应该使用
declare module 'module-name' { ... }的语法。
编写高质量的声明文件可能很复杂,需要对 TypeScript 的类型系统有深入的理解。但对于大多数开发者来说,主要是消费(而不是创建)声明文件。
tsconfig.json 中的相关配置
"noImplicitAny": true: 这是一个推荐开启的选项。当它为true时,如果 TypeScript 无法推断一个变量的类型并且没有对应的声明文件,它会报错,而不是隐式地将其视为any类型。这可以帮助你发现项目中缺少类型定义的地方。"typeRoots"和"types": 这些选项可以让你控制编译器去哪里查找声明文件,通常情况下你不需要手动配置它们。