![[TypeScript学习笔记-09]导入导出,统一模块解析](http://pic.xiahunao.cn/yaotu/[TypeScript学习笔记-09]导入导出,统一模块解析)
JavaScript 在代码模块化方面有着悠久的历史并衍生出多种不同的方法。TypeScript 自 2012 年问世以来已经实现了对许多模块化格式的支持但随着时间的推移社区和 JavaScript 规范最终都采用了名为 ES Modules或 ES6 Modules的格式。您可能熟悉它的 import/export 语法。ES Modules 于 2015 年被添加到 JavaScript 规范中到 2020 年它已在大多数 Web 浏览器和 JavaScript 运行时环境中得到广泛支持。1. 模块是如何定义的任何包含顶级import或export的文件都被视为一个模块。没有任何顶级导入或导出声明的文件将被视为脚本其内容可在全局范围内使用因此也可被模块使用。模块在其自身作用域内执行而不是在全局作用域内执行。意味着模块中声明的变量、函数、类等在模块外部是不可见的除非它们使用导出形式显式地导出要使用从其他模块导出的变量、函数、类、接口等必须使用导入表单之一进行导入。2. 非模块文件任何没有 import 声明、export 或顶级 await 的 JavaScript 文件都应被视为脚本而不是模块。在脚本文件中变量和类型被声明在共享的全局作用域中并且假定您将使用 outFile 编译器选项将多个输入文件合并到一个输出文件中或者在 HTML 中使用多个script标签来加载这些文件。如果您有一个文件当前没有任何导入或导出但您希望将其视为模块请添加以下行export{};3. TypeScript中的模块在 TypeScript 中编写基于模块的代码时需要考虑以下三个主要方面语法我希望使用什么语法来导入和导出内容模块解析模块名称或路径与磁盘上的文件之间是什么关系模块输出目标我生成的 JavaScript 模块应该是什么样子3.1 ES模块语法文件可以通过export default声明一个主导出// filename: hello.tsexportdefaultfunctionhelloWorld(){console.log(Hello, world!);}然后通过以下方式导入importhelloWorldfrom./hello.js;helloWorld();除了默认导出之外您还可以通过省略default参数来导出多个变量和函数// filename: maths.tsexportvarpi3.14;exportletsquareTwo1.41;exportconstphi1.61;exportclassRandomNumberGenerator{}exportfunctionabsolute(num:number){if(num0)returnnum*-1;returnnum;}这些可以通过导入语法在另一个文件中使用import{pi,phi,absolute}from./maths.js;console.log(pi);constabsPhiabsolute(phi);3.2 附加导入语法可以使用类似import {old as new}的格式重命名导入语句import{piasπ}from./maths.js;您可以将上述语法混合搭配合并成一个导入语句// filename: maths.tsexportconstpi3.14;exportdefaultclassRandomNumberGenerator{}// filename: app.tsimportRandomNumberGenerator,{piasπ}from./maths.js;您可以将所有导出的对象放入一个命名空间中并使用*作为名称// filename: app.tsimport*asmathfrom./maths.js;console.log(math.pi);constpositivePhimath.absolute(math.phi);你可以通过导入./file将文件导入到当前模块中而不包含任何变量。// filename: app.tsimport./maths.js;console.log(3.14);注在这种情况下导入操作本身并没有执行任何操作。然而maths.ts 中的所有代码都被执行了这可能会触发影响其他对象的副作用。3.3 TypeScript 特有的 ES 模块语法类型可以使用与 JavaScript 相同的语法进行导出和导入// filename: animal.tsexporttypeCat{breed:string;yearOfBirth:number};exportinterfaceDog{breeds:string[];yearOfBirth:number;}// filename: app.tsimport{Cat,Dog}from./animal.js;typeAnimalsCat|Dog;类型导入这是一个导入语句它只能导入类型// filename: animal.tsexporttypeCat{breed:string;yearOfBirth:number};exporttypeDog{breeds:string[];yearOfBirth:number};exportconstcreateCatName()fluffy;// filename: valid.tsimporttype{Cat,Dog}from./animal.js;exporttypeAnimalsCat|Dog;// filename: app.tsimporttype{createCatName}from./animal.js;constnamecreateCatName();// createCatName cannot be used as a value because it was imported using import type.内联类型导入TypeScript 4.5 还允许在单个导入语句前加上type前缀以表明导入的引用是一个类型// filename: app.tsimport{createCatName,typeCat,typeDog}from./animal.js;exporttypeAnimalsCat|Dog;constnamecreateCatName();3.4 基于CommonJS行为的ES模块语法TypeScript具有与CommonJS和AMD的require语句直接对应的ES模块语法。在大多数情况下使用 ES 模块导入与在这些环境中使用 require 导入相同但这种语法确保 TypeScript 文件中的内容与 CommonJS 的输出一一对应importfsrequire(fs);constcodefs.readFileSync(hello.ts,utf8);4. CommonJS 语法CommonJS 是 npm 上大多数模块所使用的格式。4.1 导出标识符是通过设置名为module的全局模块的exports属性来导出的。functionabsolute(num:number){if(num0)returnnum*-1;returnnum;}module.exports{pi:3.14,squareTwo:1.41,phi:1.61,absolute,};4.2 导入通过require语句导入这些文件constmathsrequire(./maths);console.log(maths.pi);还可以利用 JavaScript 的解构赋值特性可以稍微简化一下const{squareTwo}require(./maths);console.log(squareTwo);4.3 CommonJS 和 ES 模块互操作CommonJS 和 ES Modules 在默认导入和模块命名空间对象导入之间的区别上存在功能不匹配。TypeScript 提供了一个编译器标志可以通过--esModuleInterop来减少这两套不同约束之间的冲突5. 的模块解析选项模块解析是指从import或require语句中获取字符串并确定该字符串指向哪个文件的过程。TypeScript 包含两种解析策略Classic: 是编译器选项 module 不是 commonjs 时的默认策略它是为了向后兼容而保留的;Node模拟了 Node.js 在 CommonJS 模式下的工作方式并额外检查了.ts和.d.ts文件。TypeScript 中有很多 TSConfig 标志会影响模块策略moduleResolution、baseUrl、paths、rootDirs。6. 模块输出选项有两个选项会影响生成的 JavaScript 输出target: 它决定哪些 JS 功能会被降级转换为在旧版 JavaScript 运行时环境中运行哪些功能保持不变module: 它决定模块之间交互时使用的代码。使用哪个目标取决于你预期运行 TypeScript 代码的 JavaScript 运行时环境的功能。这可能包括支持的最早版本的 Web 浏览器;预期运行代码的最低 Node.js 版本;来自运行时环境的特殊限制。模块间的所有通信都通过模块加载器进行编译器选项模块决定使用哪个加载器。运行时模块加载器负责在执行模块之前查找并执行该模块的所有依赖项。.tsimport{valueOfPi}from./constants.js;exportconsttwoPivalueOfPi*2;ES2020import{valueOfPi}from./constants.js;exportconsttwoPivalueOfPi*2;CommonJSuse strict;Object.defineProperty(exports,__esModule,{value:true});exports.twoPivoid0;constconstants_js_1require(./constants.js);exports.twoPiconstants_js_1.valueOfPi*2;