TypeScript Module与Script的区别及路径解析规则

作者:青柠

时间:2026-10-30

浏览:84

本文深入解析TypeScript中Module与Script的核心区别,涵盖作用域、导入导出、代码管理及加载时序。详细阐述相对与非相对路径的解析机制,并介绍.d.ts文件在类型检查与智能感知中的作用,结合Worker线程示例说明后缀模块声明通配符的实际应用。

文章目录

TypeScript 中的 Module

本文主要介绍 TS 中的 module 与 non-modules 的区别;.d.ts 文件的作用;以及模块路径的解析规则;

在 TypeScript 中,若文件顶层包含 import 或 export 关键字,则该文件被视为模块;反之,若不含这些关键字,则被归类为普通脚本(Script)。

模块与脚本的区别

模块(modules)与脚本(non-modules)在多个维度上存在差异,这些差异同样适用于 JavaScript 中的模块与脚本对比(TypeScript 沿用了这一机制)。

  • 作用域上的区别

模块拥有独立的作用域。在模块内部定义的变量、函数或类仅在该模块作用域内可见,外部模块及全局脚本无法直接访问。

非模块(non-modules)运行在全局作用域(global scope)中。顶层定义的变量、函数和类均暴露于全局环境,任何外部模块或脚本均可直接访问这些内容。

  • 导出和导入

模块通过 import 和 export 关键字来控制代码的导入与导出:import 用于从其他模块引入变量、函数或类等代码段,export 用于将当前模块的代码段暴露给外部。

在非模块中,函数和变量定义于全局作用域,无需额外的导入或导出操作,可直接在全局范围内访问。

  • 代码管理

模块机制便于代码的切分与组织,开发者可根据抽象层次或功能需求进行模块化划分,从而提升代码的可维护性。

脚本代码通常集中编写在少数几个文件中,需注意变量的访问顺序,且存在污染全局作用域的风险,需采取措施规避。

  • 依赖管理

模块依赖通过 import 显式指定,允许开发者更好地控制依赖关系,从而降低命名冲突的可能性。

脚本的依赖关系是隐式的,需通过阅读代码或逐层调试才能理清;脚本按加载顺序执行,因此脚本间的加载顺序至关重要,顺序变化可能导致“函数未找到”或“变量未定义”等错误。

  • 加载时序

模块支持异步加载,代码在加载完成后才执行,这有助于减少 HTML 文档解析时的阻塞。

脚本采用经典的同步加载方式,当 HTML 中出现同步脚本时,浏览器需等待代码加载并执行完毕后,HTML 解析才会继续。通常,除部分需提前执行的代码(如权限检查、用户校验等)外,其余代码应置于 HTML 文档末尾加载(也可显式设置为异步加载)。

// oneModule.js

export function foo(params) {
    //...
}

export class Bar {
    constructor() {
        //...
    }
}
// twoModule.js

import { foo, Bar } from './oneModule.js';

export function run(){
    const ins = new Bar();

    // ...
    return foo(ins);
}

TS 中模块加载机制

模块间通过 import 和 export 建立关系,加载时路径指定分为相对路径和非相对路径两种。相对路径基于当前文件位置计算索引以定位文件;非相对路径则由编译器从包含导入语句的文件目录开始,逐级向上级目录遍历,尝试匹配对应文件。

.d.ts 文件的用法以及相关内容

在 TypeScript 中,.d.ts 文件通常用于定义 JavaScript 库或模块的类型声明。它们是描述已存在 JavaScript 代码类型信息的文件,主要描述 JavaScript 模块的结构(如导出类的参数类型、函数签名格式等),目的是方便在 TS 代码中进行类型检查和智能感知提醒。当使用 TypeScript 编写代码时,可通过类型声明文件获得对 JavaScript 库或模块的类型检查和智能感知支持。这些声明文件通常以 .d.ts 为扩展名。

通过引入适当的类型声明文件,可获得以下帮助:

  • 类型检查:类型声明文件允许 TypeScript 编译器验证代码与声明文件中定义的类型是否匹配,有助于在开发过程中捕获潜在的类型错误,并提供更强大的静态类型检查。
  • 智能感知:类型声明文件为编辑器提供库或模块的类型信息,从而支持智能感知功能。这使得在编写代码时能够获得自动完成、参数提示和文档等功能,以增加开发效率。
  • 文档化:类型声明文件还可作为库或模块的文档。通过查看类型声明文件,可了解库的可用函数、类、接口和类型等详细信息,从而更好地理解和使用它们。

案例,定义一个 worker 来实现 ThreeJS 中数据的处理:

onmessage(params) {
  //
  const data: Block[] = [];
  ... 大量计算
  // 线程计算完成返回
  postMessage({ fragments: data  }, timestamp: params.timestamp);
}
declare module '*?worker' {
  const workerConstructor:{
    new (): Worker
  };
  export default workerConstructor
}
import './worker.d.ts';
import Worker from './worker.ts?worker'
function calculateAllBlocks(threadCount: number) {
  for (let i =0; i< threadCount; i++) {
    const worker = new Worker();
    worker.onmessage = dataParse;
    // 传入参数启动线程进行计算
    worker.postMessage({..., timestamp: performance.now()});
  }
}
function dataParse(workerEvent: MessageEvent) {
  // 处理线程返回数据
}

这样我们能快速定义一个 worker.ts 线程处理模块代码,而不需要定义成js再作为参数传递进去加载执行。 main.ts 模块中使用了 Worker 类型也都合法, 原因就是导入了 worker.d.ts 来进行类型解释。

worker.d.ts 中使用了一个后缀模块声明通配符也就是“*?worker”,只有在导出模块上加上能通过校验的前后缀才能正确的匹配上(注意main.ts 中的导入)。TS中声明通配符只有在导出的时候使用了匹配上的后缀才会使用对应的类型来进行解释目标模块 。

以上就是TypeScript中Module使用区别及模块路径解析规则的详细内容,更多关于TypeScript Module模块路径的资料请关注本站其它相关文章!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章