0
点赞
收藏
分享

微信扫一扫

【TypeScript】深入学习TypeScript模块


👉 TypeScript学习:​​TypeScript从入门到精通​​ 👉 蓝桥杯真题解析:蓝桥杯Web国赛真题解析
👉 个人简介:即将大三的学生,热爱前端,热爱生活🍬
👉 你的一键三连是我更新的最大动力❤️!

🏆分享博主自用牛客网🏆:​​一个非常全面的面试刷题求职网站,真的超级好用🍬​​

前言

博主一直在牛客网刷题巩固基础知识,快来和我一起冲关升级吧!​​点击进入牛客网​​

最近博主一直在创作​​TypeScript​​​的内容,所有的​​TypeScript​​文章都在我的​​TypeScript从入门到精通​​专栏里,每一篇文章都是精心打磨的优质好文,并且非常的全面和细致,期待你的订阅❤️

本篇文章将深入去讲解​​TypeScript​​​中的模块化,这也许会是你看过的最全面最细致的​​TypeScript​​教程,点赞关注收藏不迷路🚀🚀🚀!

文章目录

  • ​​前言​​
  • ​​1、模块定义​​
  • ​​2、ES模块语法​​
  • ​​导出别名​​
  • ​​二次导出​​
  • ​​TS特定的语法​​
  • ​​3、CommonJS语法​​
  • ​​4、环境模块​​
  • ​​速记环境模块​​
  • ​​5、TypeScript模块选项​​
  • ​​模块解析选项​​
  • ​​模块输出选项​​
  • ​​6、TypeScript命名空间​​
  • ​​结语​​

1、模块定义

在​​TypeScript​​​中,就像在​​EC5​​​中一样,任何包含顶级​​import​​​ 或​​export​​ 的文件都被认为是一个模块

相反的,一个没有任何顶级导入或导出声明的文件被视为一个脚本,其内容可在全局范围内使用(因此也可用于模块)

模块在自己的范围内执行,而不是在全局范围内。这意味着在模块中声明的变量、函数、类等在模块外是不可见的,除非它们被明确地用某种导出形式导出。相反,要使用从不同模块导出的变量、函数、类、接口等,必须使用导入的形式将其导入。

​JavaScript​​​规范声明,任何没有​​export​​​ 或顶层 ​​await​​​ 的​​JavaScript​​文件都应该被认为是一个脚本而不是一个模块

如果你有一个目前没有任何导入或导出的文件,但你希望它被当作一个模块来处理,可以添加这一行:

export {};

这将改变该文件,使其成为一个什么都不输出的模块。无论你的模块目标是什么,这个语法都有效

​TypeScript​​​中能够使用​​JavaScript​​的模块化语法,并在此基础上提供了一些额外的语法

2、ES模块语法

🚗 一个文件可以通过​​export default​​ 声明一个主要出口:

// @filename: hello.ts
export default function helloWorld() {
console.log("Hello, world!");
}

一个文件中​​export default​​只能有一个

通过​​import​​导入:

// @filename: a.ts(与 hello.ts同级)
import hello from "./hello";
hello();

​import​​​引入​​export default​​​导出的内容时可以自定义导入名称,如上面导出的函数名为​​helloWorld​​​,但引入时我们自定义了​​hello​​的名称

​default​​ 出口也可以只是数值:

// @filename: hello.ts
export default "123";

// @filename: a.ts(与 hello.ts同级)
import h from "./hello";
console.log(h); // "123"

🚗 除了默认的导出,还可以通过省略​​default​​​ 的​​export​​ ,导出多个变量和函数的:

// @filename: hello.ts
export var a = 3.14;
export let b = 1.41;
export const c = 1.61;
export class D {}
export function fn(num: number) {
console.log(num);
}

可以只使用一个​​export​​导出:

var a = 3.14;
let b = 1.41;
const c = 1.61;
class D {}
function fn(num: number) {
console.log(num);
}
export { a, b, c, D, fn };

通过​​import​​​和​​{}​​实现按需导入:

// @filename: a.ts(与 hello.ts同级)
import { a, b, c, D, fn } from "./hello";
console.log(a, b, c, new D());
fn(1);

可以使用 ​​import {old as new}​​ 这样的格式来重命名一个导入:

// @filename: a.ts(与 hello.ts同级)
// 仅引入a,c,fn 并重命名a和fn
import { a as A, c, fn as FN } from "./hello";
console.log(A, c);
FN(1);

可以把所有导出的对象,用​​* as name​​​ ,把它们放到同一个命名空间​​name​​:

// @filename: a.ts(与 hello.ts同级)
// export导出的所有内容放到了命名空间 F 中
import * as F from "./hello";
console.log(F.a, F.c);
F.fn(1);

🚗​export default​​​与​​export​​一起使用:

// @filename: hello.ts
export var a = 3.14;
export let b = 1.41;
export const c = 1.61;
export class D {}
export function fn(num: number) {
console.log(num);
}
export default function helloWorld() {
console.log("Hello, world!");
}

// @filename: a.ts(与 hello.ts同级)
import hello, { a, b, c, D, fn } from "./hello";
console.log(a, b, c, new D());
fn(1);
hello();

🚗

通过​​import "file Path"​​ 导入一个文件,而不把任何变量纳入你的当前模块:

// @filename: a.ts(与 hello.ts同级)
import "./hello";

在这种情况下, ​​import​​​ 没有任何作用,但 ​​hello.ts​​ 中的所有代码都将被解析,这可能引发影响其他对象的副作用

导出别名

像导入时使用​​as​​​定义别名一样,在导出时也可以使用​​as​​定义导出的别名:

// @filename: hello.ts
const a = 1;
export { a as A };

// @filename: a.ts(与 hello.ts同级)
import { A } from "./hello";
console.log(A); // 1

二次导出

🚗 一个模块可以引入并导出另一个模块的内容,这称为二次导出,一个二次导出并不在本地导入,也不引入本地变量

​hello.ts​​:

// @filename: hello.ts
export const a = "hello";
export const n = 1;

​word.ts​​​(与​​hello.ts​​同级):

// @filename: word.ts(与hello.ts同级)
export const b = "word";
// 该模块扩展了hello.ts模块,并向外暴露hello.ts模块的a
export { a } from "./hello";

​a.ts​​​(与 ​​hello.ts​​同级):

// @filename: a.ts(与 hello.ts同级)
import { a, b } from "./word";
console.log(a, b); // hello word

🚗 另外,一个模块可以包裹一个或多个模块,并使用 ​​export * from "module "​​ 语法组合它们的所有导出

​word.ts​​​(与​​hello.ts​​同级):

// @filename: word.ts(与hello.ts同级)
export const b = "word";
// 相当于将hello.ts导出的内容全部引入后又全部导出
export * from "./hello";
// 此文件相当于导出了b和a、n(来自hello.ts)

​a.ts​​​(与 ​​hello.ts​​同级):

// @filename: a.ts(与 hello.ts同级)
import { a, b, n } from "./word";
console.log(a, b, n); // hello word 1

🚗​export * from "module "​​​ 语法也可以使用别名​​as​​​:​​export * as ns​​ 作为一种速记方法来重新导出另一个有名字的模块

​word.ts​​​(与​​hello.ts​​同级):

// @filename: word.ts(与hello.ts同级)
export const b = "word";
// 相当于将hello.ts导出的内容全部引入到命名空间H中,后又将H导出
export * as H from "./hello";

​a.ts​​​(与 ​​hello.ts​​同级):

// @filename: a.ts(与 hello.ts同级)
import { H, b } from "./word";
console.log(H.a, b, H.n); // hello word 1

TS特定的语法

类型可以使用与​​JavaScript​​值相同的语法进行导出和导入:

// @filename: hello.ts
export type Cat = {};
export interface Dog {}

// @filename: a.ts(与 hello.ts同级)
import { Cat, Dog } from "./hello";
let a: Cat, b: Dog;

​TypeScript​​​用两个概念扩展了 ​​import​​ 语法,用于声明一个类型的导入

🚗​import type​

这是一个导入语句,导入的变量只能用作类型:

// @filename: hello.ts
export const createCatName = () => "fluffy";

【TypeScript】深入学习TypeScript模块_命名空间

🚗

​TypeScript 4.5​​​还允许以​​type​​为前缀的单个导入,以表明导入的引用是一个类型:

// @filename: hello.ts
export type Cat = {};
export interface Dog {}
export const createCatName = () => "fluffy";

// @filename: a.ts(与 hello.ts同级)
// 表明Cat和Dog为类型
import { createCatName, type Cat, type Dog } from "./hello";
type Animals = Cat | Dog;
const name = createCatName();

🚗export =​import = require()​

​export =​​​ 语法指定了一个从模块导出的单一对象,这可以是一个类,接口,命名空间,函数,或枚举,当使用​​export =​​​ 导出一个模块时,必须使用​​TypeScript​​​特定的​​import module=require("module")​​ 来导入模块:

// @filename: hello.ts
const a = "hello";
export = a;

// @filename: a.ts(与 hello.ts同级)
import H = require("./hello");
console.log(H); // hello

3、CommonJS语法

若使用CommonJS语法报错,则需要先在项目根目录运行:​​npm i --save-dev @types/node​​安装声明文件

通过在一个全局调用的 ​​module​​​ 上设置 ​​exports​​ 属性来导出

// @filename: hello.ts
function absolute(num: number) {
return num;
}
const a = 3;
let b = 4;
var c = 5;

module.exports = {
a,
b,
newC: c, // 将c以newC的名称导出
d: 12, // 直接导出一个值
fn: absolute, // 将absolute以fn的名称导出
};

通过​​require​​ 语句导入:

// @filename: a.ts(与 hello.ts同级)
const m = require("./hello");
console.log(m.a, m.b, m.newC, m.fn(1));

使用​​JavaScript​​中的解构功能来简化一下:

// @filename: a.ts(与 hello.ts同级)
const { d, fn } = require("./hello");
console.log(d, fn(1));

4、环境模块

提前声明:​​declare module​​​并不仅限于​​.d.ts​​​文件,在普通​​ts​​文件中也可使用

​.d.ts​​​和​​declace​​的介绍可见大佬文章:​​ts的.d.ts和declare究竟是干嘛用的​​

我们可以使用顶级导出声明​​declare​​​在自己的​​.d.ts​​​文件中定义模块(这类似于​​命名空间​​),需要使用​​module​​关键字和模块的引用名称,这些名称将可用于以后的导入,例如:

// type.d.ts
declare module "A" {
export type a = string;
// ...
}
declare module "B" {
export type a = number;
// ...
}

上面我们在​​type.d.ts​​​声明文件中使用​​declare module​​的形式定义了两个环境模块​A​​​和​​B​​​,使用时根据环境模块的名称(​​A​​​或​​B​​​)使用​​import​​语句可直接将其导入:

import { a } from "A";
let num: a = "1"; // type num =string

导入时同样支持别名等​​import​​语法:

import * as moduleA from "A";
let num: moduleA.a = "1"; // type num =string

外部文件只能引用环境模块​​declare module​​内的类型声明

速记环境模块

如果您不想在使用新模块之前花时间写出声明,或者你的新模块还没有任何类型声明,你可以使用速记环境模块来快速定义一个空内容模块:

// type.d.ts
declare module "User";

所有来自速记模块的导入都将具有​​any​​类型:

import a, { c } from "User";
a(c);

速记模块就是空内容的环境模块,这其实没多大用处

5、TypeScript模块选项

模块解析选项

模块解析是指从​​import​​​ 或​​require​​ 语句中获取一个字符串,并确定该字符串所指的文件的过程

​TypeScript​​包括两种解析策略:

  • 经典
  • ​Node​

当编译器选项(​​tsconfig.json​​​配置文件)中 ​​module​​​ 不是​​commonjs​​ 时,经典策略是默认的,是为了向后兼容。

​Node​​​策略复制了​​Node.js​​​在​​CommonJS​​​模式下的工作方式,对​​.ts​​​ 和​​.d.ts​​ 有额外的检查

在​​TypeScript​​​中,有许多​​TSConfig​​标志影响模块策略:

  • ​​moduleResolution​​
  • ​​baseUrl​​
  • ​​paths​​
  • ​​rootDirs​​

关于这些策略如何工作的全部细节,你可以参考《​​模块解析​​》

模块输出选项

​tsconfig.json​​​配置文件中有两个选项影响​​JavaScript​​的输出:

  • ​target​​​ ,它决定了​​TS​​​代码编译成​​JS​​的版本
  • ​module​​ ,它决定了哪些代码用于模块之间的相互作用

所有模块之间的通信都是通过模块加载器进行的,编译器选项 ​​module​​ 决定了使用哪一个

在运行时,模块加载器负责在执行一个模块之前定位和执行该模块的所有依赖项

可以在​​TSConfig 模块参考​​​ 中看到所有可用的选项以及它们编译出的​​JavaScript​​代码是什么样子

6、TypeScript命名空间

​TypeScript​​​有自己的模块格式,称为 ​​命名空间(namespaces)​​​ ,这比​​ES​​模块标准要早

这种语法对于创建复杂的定义文件有很多有用的功能,并且在​​DefinitelyTyped​​​中仍然被积极使用。虽然没有被废弃,但命名空间中的大部分功能都存在于​​ES Modules​​​中,官方建议使用它来与​​JavaScript​​的方向保持一致

更多关于命名空间的信息可见: ​​【TypeScript】深入学习TypeScript命名空间​​

结语

至此,​​TypeScript​​模块化的内容就全部结束了,关注博主下篇更精彩!

博主的​​TypeScript从入门到精通专栏​​正在慢慢的补充之中,赶快关注订阅,与博主一起进步吧!期待你的三连支持。

参考资料:​​TypeScript官网​​

如果本篇文章对你有所帮助,还请客官一件四连!❤️

​​ 基础不牢,地动山摇! 快来和博主一起来牛客网刷题巩固基础知识吧!​​


举报

相关推荐

0 条评论