为什么TypeScript需要declare关键字?
\n想象一下,你在建造一栋房子,但有些房间已经存在了——它们是别人建造的(比如JavaScript库)。你无法进去重新砌墙,但你需要知道它们的布局,才能正确摆放家具。这正是TypeScript中declare关键字所扮演的角色。
如果你曾经使用过流行的库(jQuery、Lodash、D3.js),那么你一定遇到过.d.ts文件——这些就是用declare创建的“布局图”。在本文中,我们将深入探讨什么是declare,为什么需要它,以及如何在实际中使用它。准备好——会有很多代码,很少废话。
TypeScript中的declare是什么?
\ndeclare是一个关键字,它告诉TypeScript编译器:“嘿,这个东西(变量、函数、类或模块)是存在的,但它是在其他地方定义的。你只要相信我,让我在代码中使用它就行了。”
重要的是要理解:declare不会生成任何JavaScript代码。它纯粹是给编译器用的信息性结构。如果你写declare const x: number = 5,编译后x就会消失——它不会出现在最终文件中。
什么时候需要它?
\n- \n
- 处理全局变量——例如
window、document或通过CDN添加的变量。 \n - 为JavaScript库添加类型——当库是用纯JS编写的,但你希望将其与TypeScript一起使用时。 \n
- 为配置文件创建类型——CSS模块、图片、JSON文件。 \n
declare语法:基本示例
\n\n1. 变量声明
\n假设你有一个全局变量VERSION,它是在HTML文件中通过<script>定义的。TypeScript对此一无所知,因此你编写:
declare const VERSION: string;\n\nconsole.log(VERSION); // 没问题,TypeScript知道这是一个字符串\n\n编译后,declare const VERSION: string会消失,而console.log(VERSION)会保留。
2. 函数声明
\n假设你有一个来自分析工具的全局函数trackEvent:
declare function trackEvent(eventName: string, properties?: Record<string, any>): void;\n\n// 使用\ntrackEvent("button_click", { buttonId: "submit" });\n\n编译器不会检查实现——它只知道函数签名。
\n\n3. 类声明
\n一个库提供了全局命名空间中的Moment类:
declare class Moment {\n constructor(date: string);\n format(pattern: string): string;\n}\n\n// 使用\nconst now = new Moment("2024-01-01");\nconsole.log(now.format("YYYY-MM-DD"));\n\n\n4. 模块声明
\n这是最常见的场景。例如,你有CSS模块或JSON文件:
\n// styles.d.ts\ndeclare module "*.css" {\n const styles: Record<string, string>;\n export default styles;\n}\n\n// images.d.ts\ndeclare module "*.png" {\n const src: string;\n export default src;\n}\n\n现在你可以导入CSS和图片而不会出现TypeScript错误。
\n\ndeclare和.d.ts文件
\n扩展名为.d.ts的文件(类型声明文件)是declare关键字的“栖息地”。它们只包含声明,不会编译成JavaScript。通常它们位于types/文件夹中,或者随库一起提供(例如@types/lodash)。
示例:为jQuery创建类型
\n