TS 导入导出那些事
一、前言
最近用 TypeScript 写 npm 包,各种模块、命名空间、全局定义等等扰得我睡不着觉。我便苦心研究,总结了几个比较冷门的,国内貌似基本上找不到资料的导入导出用法,顺便在其中又插入一些不那么冷门的用法,于是本篇文章来了。
二、导入模块
导入模块主要分为 2 种:
导入 ESM 模块
导入平常的 ES Module 中的东西相信大家都不陌生。唯一需要注意的便是默认导出与“星号”式导入的区别。
“星号”式导入:
导入模块的默认导出:
命名的方式导入模块:
导入 CJS 模块
导入 CommonJS 模块和 ES Module 稍有不同。主要是因为面向 CJS 的模块会有导出分配。
如果最终模块是个对象,则可以使用同 ESM 一样的方式导入。
如果模块是个函数或者基本数据类型之类的,则要用以下这种方式
实际上具体使用哪种还是有点混乱的,主旨思想是只要引入不报错就行。
三、在模块中导出
在模块中导出东西相信大家也不陌生,不过这里还是详细讲解一下。
在模块中导出东西有很多种方法。导出总共可分为 4 类:
命名导出
命名导出有两种方法,一种是声明着导出
一种是声明后导出
声明后导出比声明着导出更灵活,能合并,也能重命名
命名导出编译成 Common JS 后类似这样
需要注意的是其他人无法修改任何你导出的东西。即使是使用 let
声明也一样
不过对于上面的代码,你可以随便修改所导出的 a
。因为其他人每次读取 a
时都会重新从你的导出对象上访问一次 a
属性,不用担心其他人无法接收到你的修改。具体可以查看编译后的 JS 文件
默认导出
默认导出可以理解为一种特殊的命名导出。
默认导出的名字是 default
。但是你不能搞个名字叫 default
的变量然后导出,你必须得用 export default
或者在导出时重命名
星号导入搭配默认导出,可以达到默认导出即为星号导出的效果
导出分配
导出分配就是把 Common JS 的导出搬到了 TS 中。写法也差不多
导出分配也可以指定默认导出,只需要有 default
属性就可以
需要注意的是采用了导出分配后便不能再使用其他导出方法。
导出其他模块
导出其他模块一般分为两种。
第一种是星号导出,把其他模块的东西全导出到自己里头,就像
具体效果是 xxx
中导出的东西,也可以通过你访问到。
第二种是挂到自己模块下面,既可以是这样
也可以是这样
二者主要的区别在于前者仅仅是导出了模块,其他什么都没干;而后者实际上还引入了模块,为模块注册了标识符,让你在导出的同时还可以通过 xxx
访问到 ./xxx 模块。
如果只想把另一个模块的一部分东西导出出去,还有这种方法
四、导入命名空间
虽然现在命名空间相较于模块并不是特别常用,但它还是有比较完整的导入导出功能的。
导入命名空间中的东西很简单,像这样
不论你是在模块中导入全局命名空间,还是在命名空间中导入其他命名空间,都是适用的。
较为可惜的是命名空间貌似没有星号导入,也不支持解构导入。
五、在命名空间中导出
在一般 TS 中,命名空间只有两种方法导出。
第一种方法是声明着导出,类似于模块
第二种方法是导入着导出,可以用来导出其他命名空间的东西
而对于不一般的 TS ——也就是类型声明中,命名空间还可以采用像模块一样的导出对象
六、使用全局定义
全局定义一般有三种:
内置在 TS 中的全局定义。比如
setTimeout
、Error
等。对于这种全局定义,直接拿来用就可以了。位于环境模块中的全局定义。比如
NodeJS.Process
等。包括位于
node_modules/@types
文件夹中的自动引入的环境模块,都可以通过三斜杠注释来引入。你可以通过
path
直接指定文件路径/// <reference path="./types.d.ts" />
位于模块中的全局定义。
这种全局定义只需要引入一下模块,表示你已经运行此模块,即可
import '@babel/core';
或者你也可以通过三斜杠注释,通过
types
指定模块/// <reference types="@babel/core" />
需要注意的是,不论你采用
import
还是三斜杠注释,甚至只是在类型中使用了一个typeof import('xxx')
,只要你在一个 TS 文件中引入了这个模块所定义的全局类型,那这个类型就会永远存在下去,污染你的globalThis
。唯一在不污染全局域的情况下运行模块的方法是使用import()
函数动态引入,但这样子你也拿不到你需要的类型。
七、进行全局定义
进行全局定义一般有三种方法。
第一种是直接写环境模块。不带任何 import
和 export
一般就会让编译器把这当成一个环境模块。所以,如果你需要防止一个 TS 文件变成环境模块导致类型泄露的话,你可以加一个安全无公害的 export { };
。
第二种是在模块中定义,只需要把类型定义写到 declare global
里头就行
第三种是通过合并 globalThis
命名空间来定义,好处是可以使用命名空间的“导入着导出”方法,将模块或者其他命名空间的局部变量变成全局变量
相关内容拓展:(技术前沿)
近 10 年间,甚至连传统企业都开始大面积数字化时,我们发现开发内部工具的过程中,大量的页面、场景、组件等在不断重复,这种重复造轮子的工作,浪费工程师的大量时间。
针对这类问题,低代码把某些重复出现的场景、流程,具象化成一个个组件、api、数据库接口,避免了重复造轮子。极大的提高了程序员的生产效率。
推荐一款程序员都应该知道的软件 JNPF 快速开发平台,采用业内领先的 SpringBoot 微服务架构、支持 SpringCloud 模式,完善了平台的扩增基础,满足了系统快速开发、灵活拓展、无缝集成和高性能应用等综合能力;采用前后端分离模式,前端和后端的开发人员可分工合作负责不同板块,省事又便捷。
免费体验官网:https://www.jnpfsoft.com/?infoq
还没有了解低代码这项技术可以赶紧体验学习!
版权声明: 本文为 InfoQ 作者【这我可不懂】的原创文章。
原文链接:【http://xie.infoq.cn/article/5fae8798045aa24ce7fe2d14c】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论