TS学习(六) :TS的模块化使用

在讲模块化之前,我们线了解一些前端领域中有哪些模块化标准:ES6、commonjs、amd、umd、system、esnext(这个还没有正式成为模块化标准)

那么这么多模块化标准,我们在TS中所讨论的是ES6和commonjs,他们是如何书写模块化语句?书写完成后编译结果是如何的

TS中如何书写模块化语句

TS中,导入和到处模块化,同一使用ES6的模块化标准,如下例子

//myModule.ts文件
export function sum(a:number,b:number):number{
    return a+b
}
export const name="井底的蜗牛"

//index.ts 文件
import {name, sum} from "./myModule";
console.log(sum(3,4))
console.log(name)

在使用导出的函数和变量时,你会发现它会自动帮你把import {name, sum} from "./myModule";导入,不需要手动导入

当然前提条件是,在导出的时候,导出的是一个声明export 声明变量/函数,而不是默认导出的形式export defailt {}如:

//myModule.ts文件
export default {
    name:'井底的蜗牛',
    sum(a:number,b:number):number{
        return a+b
    }
}

因为默认导出的对象是没有名字的,所以在导入时,是可以更改导入的名字的,所以无法享受到它的自动导入

//index.ts 文件
import myModule from "./myModule";
console.log(myModule.sum(3,4))
console.log(myModule.name)

这里值得注意:在导入的时候,文件名字不要加后缀名import myModule from "./myModule.ts";因为在编译结果中是没有ts文件的 你加入ts后缀编译后根本找不到该文件这样必定报错

在TS中使用模块还是挺简单的,就使用ES6的模块化标准就可以了

编译结果中的模块化

到了js代码中,世界其实没有那么清净的,本来我们写代码的时候都使用的是ES6模块化标准,但到了真实的世界是混乱的,一会儿是ES6标准,一会儿是commonjs标准,那么编译结果里面是怎么处理的,使用的是什么模块化标准呢?

首先编译结果是可以配置的,啥意思呢,就是编译结果使用ES6还是commonjs标准是可以进行配置的,既然可以配置那么在哪里配置呢,既然是配置那肯定是配置文件了

我们可以在TS的配置文件tsconfig.json中进行配置,是哪个配置呢,就是module这个配置

{
    "compilerOptions": {
        "target": "es2016",//配置编译目标代码的版本标准
        "module": "commonjs",//配置编译目标使用的模块化标准
        "lib": ["es2016"], //表示默认详情下ts使用的是那一个环境
        "outDir": "./dist",//编译结果的目录
        "strictNullChecks": true,//TS检查变量是否是null
        "removeComments": true,/*编译结果中是否移除注释*/
        "noImplicitUseStrict": true,/*编译结果中是否有"use strict"*/
    },
    "include":["./src/index.ts"],//执行ts的目录
}

配置编译结果为 commonjs时的情况

当我们配置为"module": "commonjs"时,编译的结果使用的就是commonjs的标准,这里使用的是声明变量导出,编译的结果如

//编译后的myModule.js文件
Object.defineProperty(exports, "__esModule", { value: true });
exports.name = exports.sum = void 0;
function sum(a, b) {
    return a + b;
}
exports.sum = sum;
exports.name = "井底的蜗牛";

//编译后的index.js文件
Object.defineProperty(exports, "__esModule", { value: true });
const myModule_1 = require("./myModule");
console.log((0, myModule_1.sum)(1, 4));
console.log(myModule_1.name);

当我们的文件使用的是默认导出,编译的结果如下:

在原文件myModule.ts 在该文件中加入一个默认导出一个函数

//原文件myModule.ts
export function sum(a:number,b:number):number{
    return a+b
}
export let name="井底的蜗牛"
export default function (){
    console.log("this is myModule!")
}

结果编译结果中就变成了这样,我们可以看出,由于commonjs导出的是一个exports对象,所以默认的导出会变成exports的default属性

//编译后的myModule.js
Object.defineProperty(exports, "__esModule", { value: true });
exports.name = exports.sum = void 0;
function sum(a, b) {
    return a + b;
}
exports.sum = sum;
exports.name = "井底的蜗牛";
function default_1() {
    console.log("Hello myModule!");
}
exports.default = default_1;

我们在导入时给默认导出的函数命名为sayHell

//原文件index.ts
import sayHell,{name, sum} from "./myModule";

console.log(sum(1,4))
console.log(name)
sayHell()

结果到编译结果中,commonjs导入的是myModule_1整个对象,而刚刚命名的默认导出的名字就变成了,myModule_1.default()执行,因为导出的时候就是这样导出的, 所以在导入的时候,不管你名字是啥,编译后都是myModule_1.default

//编译后的index.js
Object.defineProperty(exports, "__esModule", { value: true });
const myModule_1 = require("./myModule");
console.log((0, myModule_1.sum)(1, 4));
console.log(myModule_1.name);
(0, myModule_1.default)();

配置编译结果为 es6时的情况

在配置编译结果为es6时,发现导出时的编译结果和原文件一模一样

//原文件 myModule.ts
export function sum(a:number,b:number):number{
    return a+b
}
export let name="井底的蜗牛"
export default function (){
    console.log("Hello myModule!")
}

//编译后的结果
export function sum(a, b) {
    return a + b;
}
export let name = "井底的蜗牛";
export default function () {
    console.log("Hello myModule!");
}

导入时,不会像commonjs一样,把默认导入的名字给替换,它还是sayHello

//原文件 index.ts
import sayHell,{name, sum} from "./myModule";

console.log(sum(1,4))
console.log(name)
sayHell()

//编译结果
import sayHell, { name, sum } from "./myModule";
console.log(sum(1, 4));
console.log(name);
sayHell();

总结:TS中发模块化在编译结果中

  • 如果编译结果的模块化标准是ES6:没有区别
  • 如果编译结果的模块化标准是commonjs:
    • 导出:导出的声明会变成exports的属性,默认的导出会变成exports的default属性;
    • 导入:导入时给默认导出命的名字会变成,导出对象的default属性,而不是使用导入时的名字

温馨小提示

当我们在TS中导入node的一些包时,如import fs from 'fs',他可能会报错,提示说fs没有默认导出,

//原文件 index.ts
import fs from 'fs'
fs.readFileSync('./')

编译后的结果是长这样的,因为import fs from 'fs'这个就相当于commonjs中的默认导入,而fs模块本身导出就是module.exports={}这种形式 所以编译后就会变成一个对象的default属性,然后去default属性中找readFileSync方法,这当然没有所以报错

//编译后的文件 index.js
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = require("fs");
fs_1.default.readFileSync('./');

如何解决这种报错,有三种方法

  • 1、在我们导入时使用import {readFileSync} from 'fs'这种按需导入的方式,就不会报错了,编译的结果如下
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = require("fs");
(0, fs_1.readFileSync)('./');
  • 2、导入时 import * as fs from 'fs' 用这种方式进行导入,也可正常使用,当然编译结果和第一种是一样的
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
fs.readFileSync('./');
  • 3、在tsconfig.json配置文件中加入"esModuleInterop": true,进行配置,它的作用就是启用es模块化交互非es模块导出, 然后我们还是使用import fs from 'fs',他就不报错了,然后我们看看编译结果 发现多了一个__importDefault的辅助函数
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
fs_1.default.readFileSync('./');

温馨提示2

如何在TS中使用commonjs?看下面例子

一般我们是这样用commonjs进行导出的

//导出原文件文件,myModule.ts
module.exports = {
    name:'井底的蜗牛',
    sum(a:number,b:number):number{
        return a+b
    }
}

编译后的结果与原来的是没有变化的

//编译后的文件 myModule.ts
module.exports = {
    name: '井底的蜗牛',
    sum(a, b) {
        return a + b;
    }
};

然而在导入时,会发现使用commonjs导入,const myModule = require("./myModule")没有类型检查,它检查的结果是any类型,编译后的结果也是一样的

如果想要获取类型检查,最好使用es6的模块化导入导出,当然如果你还是想要使用commonjs进行导入导出,你可以进行如下操作

  • 在导出的时候你不要使用 module.exports ={}的方式导出,而是使用export={}的方式进行导出,编译的结果和使用module.exports ={}的方式是一样的,不同的地方就是使用export={}有类型检查
//原文件 myModule.ts
export = {
    name:'井底的蜗牛',
    sum(a:number,b:number):number{
        return a+b
    }
}
//编译后的文件 myModule.js
module.exports = {
    name: '井底的蜗牛',
    sum(a, b) {
        return a + b;
    }
};
  • 导入的时候也不要使用const myModule = require("./myModule")方式了,由于你在配置文件中添加了esModuleInterop为true的配置,

    那么你就可以使用es6的方式进行导入import myModule from './myModule'

    如果你硬要使用require的方式进行导入,那么你可以这样写import myModule = require("./myModule") 在使用的时候就可以看到其属性的类型了

当然在TS中最好使用ES6的模块化导入导出

模块化解析

模块化解析应该从什么位置寻找模块的呢

TS中,有两种模块解析策略

  • classic: 经典(已过时了) -node:node解析策略,和node解析策略一样,不过唯一的变化就是将js替换为ts
    • 相对路径:require("./xxx"),它先找当前目录下有没有这个文件,如果没有,就看package.json中有没有"main":"xxx.ts"这个配置,他就会找./xxx这个文件夹下有没有xxx.ts这个文件,如果还是没有,就会去找这个文件夹下有没有index.xx这个文件
    • 非相对模块 require("xxx"),它是去找node_modules目录下当前文件夹有没有该文件,如果没有就一层一层网上找
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在Vue、Vuex和TypeScript中使用modules进行模块化的方式如下: 首先,我们需要安装好Vue和Vuex,并使用TypeScript构建Vue项目。可以通过以下命令进行安装: ``` npm install vue vuex --save npm install typescript ts-loader --save-dev ``` 接下来,在根目录下创建`store`目录,并在该目录下创建`index.ts`文件。在`store`目录下再创建`modules`目录,并在该目录下创建对应的模块文件,例如`user.ts`和`product.ts`。 在`user.ts`模块中,定义用户相关的状态、mutations、actions和getters。例如: ```javascript // user.ts const user = { state: { userInfo: null }, mutations: { SET_USER_INFO(state, userInfo) { state.userInfo = userInfo; } }, actions: { setUserInfo({ commit }, userInfo) { commit('SET_USER_INFO', userInfo); } }, getters: { getUserInfo: state => state.userInfo } }; export default user; ``` 在`product.ts`模块中,同样定义商品相关的状态、mutations、actions和getters。 在`index.ts`文件中,引入Vue和Vuex,并创建一个Vuex Store对象,使用`module`方法将模块添加到Store中。例如: ```javascript // index.ts import Vue from 'vue'; import Vuex from 'vuex'; import user from './modules/user'; import product from './modules/product'; Vue.use(Vuex); const store = new Vuex.Store({ modules: { user, product } }); export default store; ``` 最后,在Vue的入口文件(如`main.ts`)中,引入创建的Vuex Store,并将其挂载到Vue实例上。例如: ```javascript // main.ts import Vue from 'vue'; import App from './App.vue'; import store from './store/index'; Vue.config.productionTip = false; new Vue({ store, render: h => h(App) }).$mount('#app'); ``` 现在,我们就可以在组件中使用`this.$store`来访问Vuex的状态、提交mutations、触发actions等。在模块化的情况下,可以使用`this.$store.state.user.userInfo`来访问`user`模块中的`userInfo`状态,使用`this.$store.commit('user/SET_USER_INFO', userInfo)`来提交`user`模块中的`SET_USER_INFO`mutation,使用`this.$store.dispatch('user/setUserInfo', userInfo)`来触发`user`模块中的`setUserInfo`action,以此类推。 通过以上的步骤,我们就可以在Vue、Vuex和TypeScript中使用modules进行模块化管理应用的状态。这样可以使得代码结构更清晰,易于维护和扩展。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值