简体中文
  • typescript
  • javascript
  • nodejs
  • node_modules
  • module-augmentation

TypeScript 模块的增强和处理嵌套的 JavaScript 文件

学习 TypeScript 中的模块增强基础知识,以及如何为嵌套的 JavaScript 文件添加类型定义。

Gao
Gao
Founder

TypeScript 已成为 JavaScript 生态系统中非常宝贵的补充,超过十年来因其能够为 JavaScript 代码提供类型安全而备受欢迎。

JavaScript 包的类型

为了向后兼容性和灵活性,TypeScript 允许包作者为他们的 JavaScript 包提供类型定义。这些类型定义通常存储在 "DefinitelyTyped" 仓库中。你可以使用 @types 作用域来安装这些类型定义,例如,@types/react 是 React 包的类型定义。

安装这些类型定义之后,你可以自信地使用该包,并确保类型安全性。以下是使用类型安全性定义 React 组件的示例:

模块增强

虽然大多数流行的 JavaScript 包在 @types 作用域中已有现成的类型定义,有些包可能缺少类型定义或类型定义已过时。在这种情况下,TypeScript 提供了一个强大的功能,称为 "模块增强",用于为这些包添加类型定义。我们来看一个示例:

现在你可以在代码中使用这个增强的类型定义了:

模块增强不仅允许你为包添加类型定义,还可以扩展现有的类型定义。例如,你可以为 window 对象添加一个新属性:

并在代码中使用它:

之前的文章 中,我们讨论了 React Router 库中的一个类型问题,并且通过扩展和增强现有类型在自定义声明文件中克服了这个影响。

请记住,在使用模块增强时,通过仔细检查 JavaScript 源代码,以确保类型定义的准确性至关重要。不正确的类型定义可能会导致运行时错误。在上述示例中,window.foo 属性必须是存在于 window 对象上的一个字符串。

全局增强

有时你可能会遇到引入全局变量的脚本,你可能希望为这些全局变量提供类型定义,以便在 TypeScript 代码中使用它们。例如,如果你有一个设置了名为 __DEV__ 的全局变量的脚本:

你可以为这个全局变量添加类型定义,如下所示:

现在你可以在 TypeScript 代码中使用它了:

通过结合模块增强和全局增强,你甚至可以扩展 JavaScript 原型的类型定义。然而,通常不推荐这样做,因为它可能会污染全局作用域。

模块增强的强大功能允许进行这种扩展,但需要谨慎操作,以防止污染全局作用域。

嵌套的 JavaScript 文件

在前面提到的示例中,我们假设导入可以通过包的入口文件解析。然而,有些包会导出没有相应类型定义的嵌套 JavaScript 文件。考虑一个名为 foo 的包,它具有以下结构:

foo 包导出 index.js 文件作为入口点,并且还导出 bar 目录。

要增强 foo 包的类型定义,你可以创建一个 foo.d.ts 文件:

然而,如果你尝试在 TypeScript 中导入 baz.js 文件,将会遇到错误:

为了增强 baz.js 文件的类型定义,你需要创建一个单独的 baz.d.ts 文件:

这可以确保 TypeScript 能够定位模块及其关联的类型定义:

为了保持类型定义的有序性,你可以在类型定义文件中模仿包的结构:

这种方法使你的 TypeScript 代码保持结构化并且类型安全,即使是在处理嵌套的 JavaScript 文件时。