👀TypeScript防脱发级入门——模块化

1,114 阅读7分钟

嗨!大家好!我是法医,一只治疗系前端码猿🐒,与代码对话,倾听它们心底的呼声,期待着大家的点赞👍与关注➕。

TS模块化

1. TS中如何书写模块化

TS中,导入和导出模块,建议统一使用ES6的模块化标准

新建module.ts文件,导出变量name函数numRes

//导出变量name和函数numRes
export const name = "法医";

export function numRes(num1:number,num2:number) {
    return num1 + num2;
}

新建index.ts文件,用于导入namenumRes

import { name, numRes } from "./myModule";

console.log(name);//输出 “法医”
console.log(numRes(1,2));// 打印 3

在TS中使用模块化是比较简单的,并且我们在导入的时候是不需要自己写import的,可以利用TS的智能提示,如下:

GIF 2021-9-14 11-15-11.gif

想要利用TS的智能提示有个前提,那就是在导出文件的时候需要使用普通的导出方式,而不是默认的导出方式,默认导出是没有智能提示的

//普通导出有智能提示
export const name = "法医";

export function numRes(num1:number,num2:number) {
    return num1 + num2;
}

//默认导出没有智能提示
export default {
    name: "法医",
    numRes:function (num1:number,num2:number) {
        return num1 + num2;
    }
}

还有一个点需要注意,就是在导入模块的时候不要加后缀名tsimport { name, numRes } from "./myModule.ts";

image.png

之所以会报错,是因为导入模块文件会进行编译,如果存在ts后缀名,在编译后的js文件中找不到ts文件的,所以会报错

2. 编译结果的模块化

TS中使用模块化,有时会使用ES6模块化,有时使用CommonJS模块化,所以也是有必要了解编译后的JS使用的是哪种模块化标准。

首先我们应该清楚一点,关于编译结果中的到底使用哪种模块化是可配置的,配置文件是tsconfig.json中的module属性,它就是用来配置编译后的JS文件是使用哪种模块化标准的

{
  "compilerOptions": {//配置编译选项
    "target": "es2016",//编译时用的哪一套ES标准
    "module": "es6",//配置编译目标使用的模块化标准,commjs是node环境中的标准,es6也可以
    "lib": ["ES2016"],//默认是有dom环境的,但现在用不到,这里面是没有node环境配置的,需要安装第三方库
    "outDir": "./dist",//将编译的结果放在哪个目录下面
    "strictNullChecks": true,//表示更加严格的空类型检查
  },
}
  • 使用ES6标准对比编译前和编译后

    es6模块化导出:

    image.png

    由于在TS里面本身使用的是ES6的标准,而对编译结果配置的时候也是ES6的标准,所以从代码来看,两者没有任何区别的,编译结果只是取消了类型约束。

    es6模块化导入:

    image.png

    从代码来看使用es6模块导入也是一模一样,没有任何区别的

    👉 小知识:

    从前后编译的结果来看,当TS代码中有注释的时候,编译后的JS文件也是会有注释的,如果不希望注释被编译到结果中,此时可以在tsconfig.json进行配置 "removeComments": true,//表示移除注释,配置如下:

    {
      "compilerOptions": {//配置编译选项
        "target": "es2016",//编译时用的哪一套ES标准
        "module": "es6",//配置编译目标使用的模块化标准,commjs是node环境中的标准,es6也可以
        "lib": ["ES2016"],//默认是有dom环境的,但现在用不到,这里面是没有node环境配置的,需要安装第三方库
        "outDir": "./dist",//将编译的结果放在哪个目录下面
        "strictNullChecks": true,//表示更加严格的空类型检查
        "removeComments": true,//表示移除注释
      },
    }
    
  • 使用CommonJS对比编译前和编译后

    CommonJS模块化导出:

    image.png

    当我们使用commonJs模块化导出的时候,会发现编译后的结果跟编译前有很大差异,在JS文件中会发现第一行是use strict严格模式,其实use strict是没必要出现在编译结果中的,因为我们写的TS代码本身够严格了,因此我们可以进行配置:

    {
      "compilerOptions": {//配置编译选项
        "target": "es2016",//编译时用的哪一套ES标准
        "module": "CommonJS",//配置编译目标使用的模块化标准,commjs是node环境中的标准,es6也可以
        "lib": ["ES2016"],//默认是有dom环境的,但现在用不到,这里面是没有node环境配置的,需要安装第三方库
        "outDir": "./dist",//将编译的结果放在哪个目录下面
        "strictNullChecks": true,//表示更加严格的空类型检查
        "removeComments": true,//表示移除注释
        "noImplicitUseStrict": true,//表示编译结果中不包含use strict
      },
    }
    

    接下来我们看这一行代码Object.defineProperty(exports, "__esModule", { value: true });这行代码圣骑士相当于exports._esModule = true;至于有什么作用这里先不说,一会说。

    CommonJS模块化导入:

    image.png

    commonJs中是没有import..from..的,它只能通过require方式导入,在编译后的结果里它会自动声明一个变量,也就是上述代码中的myModule_1,这个变量是文件名 + "_" + 编号,如果有多次导入的话,编号会依次自增。

    在开发过程中很多时候不需要关心导入导出编译的结果是什么,但是了解这个编译结果对处理细节问题上是有帮助的

    总结:

    • 如果编译结果的模块化标准是ES6:没有区别
    • 如果编结果的模块化标准是commonjs:导出的声明会变成exports的属性,默认导出会变成exports的default属性

    有的时候我们会遇到比较特殊的情况,比如说我们想使用node里面的fs,此时会报错,比如说:

    image.png

3. 解决默认导入的错误

这部分研究在TS中使用默认导出时产生报错的问题,想要知道什么原因导致的,其实看看编译后的结果也就明白了

image.png

从代码中看,fs提示没有默认导出,这里报错的原因是fs不是通过TS写的,在fs模块里面它是通过module.exports = {}方式导出的,因此导入的时候加一个default,那肯定是不行的,这时候我们可以这么处理:

image.png

之所以会产生这么个问题,是因为有些模块不是我们自己写的,我们自己写直接统一使用ES6模块就可以了,不会有什么问题,但是以前有些模块使用module.exports = {}方式导出的,这就很尴尬,只能寻找其它解决办法,上述是其中一种办法,但是这种方式不太好,因为fs对象里面不仅仅只有一个函数,有很多,总不能挨个写一遍把,这肯定是太麻烦了,然而我们可以导入所有内容,然后起个别名这种方式处理:

image.png

但是对于有强迫症的人来说,我就不想用这种方式,那么还有最后一个办法,在tsconfig.json中配置"esModuleInterop":true,意思是启动es模块化交互非es模块导出

{
  "compilerOptions": {//配置编译选项
    "target": "es2016",//编译时用的哪一套ES标准
    "module": "CommonJS",//配置编译目标使用的模块化标准,commjs是node环境中的标准,es6也可以
    "lib": ["ES2016"],//默认是有dom环境的,但现在用不到,这里面是没有node环境配置的,需要安装第三方库
    "outDir": "./dist",//将编译的结果放在哪个目录下面
    "strictNullChecks": true,//表示更加严格的空类型检查
    "removeComments": true,//表示移除注释
    "noImplicitUseStrict": true,//表示编译结果中不包含use strict
    "esModuleInterop":true,//启动es模块化交互非es模块导出    
  },
}

配置之后,代码不会报错了

image.png

4. 在TS中如何使用CommonJs导入导出

  • 导出:export = xxx;

    //举个栗子
    export = {
        name:"法医",
        sayHello(a:string,b:string){
            return a + b;
        }
    }
    
  • 导入:import xxx = require("xxx");

    //举个栗子
    import module = require("myModule");
    

最后

很感谢小伙伴看到最后😘,如果您觉得这篇文章有帮助到您的的话不妨关注➕+点赞👍+收藏📌+评论📜,您的支持就是我更新的最大动力。