*.d.ts 的秘密:TypeScript 如何理解外部代码

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么你的代码能与 lodash 和谐共处?

你是否曾好奇过,TypeScript 是如何知道像 lodash 或 jQuery 这样的普通 JavaScript 库的类型的?你只是写了 import _ from 'lodash',然后突然就有了自动补全和类型检查。是魔法吗?不,这是神秘的 *.d.ts 文件在起作用。

在 Stack Overflow 上,“About "*.d.ts" in TypeScript”这个问题获得了数千次浏览——开发者们想了解这个扩展名背后隐藏着什么。今天,我们将深入 TypeScript 内部,剖析类型声明的工作原理。你不仅会学到理论知识,还会获得实用的示例,帮助你为任何 JavaScript 项目创建自己的类型。



.d.ts 到底是什么?

扩展名为 .d.ts 的文件是 TypeScript 声明文件。它们只包含类型描述,而不包含实现。可以把它们想象成一份“契约”:TypeScript 查看这个文件,就能理解存在哪些函数、类和变量,以及它们的类型是什么。

与普通 .ts 文件的关键区别在于:.d.ts 不会编译成 JavaScript。它们仅用于静态分析和自动补全。



// myLibrary.d.tsexport function greet(name: string): void;export const VERSION: string;


现在,如果你导入这个库,TypeScript 就会知道:greet 接受一个字符串且不返回任何值,而 VERSION 是一个字符串。如果没有这个文件,你会收到错误信息“Could not find a declaration file for module”。



TypeScript 如何找到 .d.ts?

声明文件的查找机制分几个步骤进行:

  • 自动查找:如果 .js 文件旁边有一个同名的 .d.ts 文件,TypeScript 会自动加载它。
  • package.json 中的 types 或 typings 字段:许多库会指定其声明文件的路径。例如:"types": "./lib/index.d.ts"。
  • /// <reference path="" /> 指令:手动指定声明文件(一种较旧但仍然存在的方法)。
  • @types 包:如果库本身不包含类型,社区会将其发布到 npm,名称为 @types/库名。

当你运行 npm install @types/react 时,你下载的正是描述 React 的一组 .d.ts 文件。



内部原理:TypeScript 如何处理 .d.ts

让我们想象一下,TypeScript 是一名侦探,正在调查一桩“类型案件”。.d.ts 文件就是证人的证词。它们说:“这里有一个 add 函数,它接受两个数字并返回一个数字”。TypeScript 相信这些证词,并且不会去验证它们是否属实(因为没有实现)。



Ambient 声明

.d.ts 最强大的功能之一就是声明 ambient 模块。这允许你为代码中不存在的模块描述类型。例如,你想使用 jQuery 中的全局变量 $:



// globals.d.tsdeclare var $: (selector: string) => any;


或者描述整个模块:



// my-custom-module.d.tsdeclare module 'my-custom-module' {    export function doSomething(x: number): string;    export interface Config {        timeout: number;    }}


现在,你可以编写 import { doSomething } from 'my-custom-module'——TypeScript 就会知道这些类型。



全局类型 vs 模块类型

一个重要的区别:.d.ts 文件可以是全局的(如果其中没有 import/export),也可以是模块化的(如果有)。全局声明可见

博客

书籍推荐