问题背景:
许多 JavaScript 生态系统中的库只提供原始的 js 文件,而没有自己的类型。为了描述第三方或自定义库以及全局变量的类型,TypeScript 实现了一种特殊格式的文件,扩展名为 .d.ts(声明文件)。它们已经成为确保项目中类型信息和类型安全的标准,适用于任何 js 模块之上。
问题:
如果没有为第三方 JS 模块定义类型,TypeScript 被迫将这些导入视为 any,这意味着你失去了所有静态类型检查的优势:在调用、不存在的字段、不正确的参数上的错误逻辑上能够通过编译,并且只在代码运行后才会被发现。也无法进行自动补全和类型导航。
解决方案:
通过声明文件,可以手动为任何 JS 代码描述类型:函数、类、对象、命名空间甚至全局常量。因此,无论外部库的来源如何,项目都保持类型安全。
代码示例:
// hello.d.ts declare module 'hello' { export function sayHello(name: string): string; } // app.ts import { sayHello } from 'hello'; sayHello('TypeScript'); // 类型安全
关键特点:
可以直接在声明文件中声明函数的实现吗?
不可以,声明文件中只允许声明结构和签名,而不能实现它们。任何函数体的存在都会触发编译错误。
// 不可以: declare function sum(a: number, b: number) { return a + b; }
如果流行的 npm 模块没有原始包中的类型,在哪里寻找它们?
在 DefinitelyTyped 仓库(npm 包 @types/<lib>):几乎所有流行的包都有以单独 npm 模块形式提供的当前类型定义。
可以使用 d.ts 文件描述全局变量(不通过 import)吗?
可以,通过 ambient declarations 机制,例如,declare var VERSION: string;。这对于描述 window.X、全局常量和变量非常方便。
** 负面案例 项目使用没有类型定义的 JS 库。开发人员忘记了 d.ts 文件,通过 any 访问 API。在更新库时出现错误:旧的调用崩溃,但编译器没有注意到。
优点:
缺点:
** 正面案例 为当前库开发了自定义 d.ts 文件,签名保持最新状态,使用 IDE 的自动补全和导航。
优点:
缺点: