TS从入门到放弃【十六】:模块和命名空间
TS 和 ES6 保持一种,包含顶级的 import
和 export
的文件都被当作成一个模块,模块中定义的内容仅模块内可见,而不是全局可见。
TS 模块除了遵循 ES6 标准的语法外,还有一些特定的语法。
1、模块
(1)export
TS 中仍然使用 export
来导出声明,而且不仅可以导出:变量、函数、类,还可以导出 TS 中特有的 类型别名和接口
- 导出接口:
export interface FuncInterface {
name: string;
(arg: number): string;
}
- 导出类:
export class ClaccC {
constructor() {}
}
- 导出类的另外方式:
class ClassD {
constructor() {}
}
export { ClassD };
export { ClassD as ClassNamedD };
- 导出其他模块的全部内容:
// b,ts
export const name = 'dylan'
export const age = 18
// a.ts
export * from './b.ts'
- 导出其他模块的部分内容:
// b,ts
export const name = 'dylan'
export const age = 18
// a.ts
export { name } from './b.ts'
export { name as NameProp } from './b.ts' // 起别名
(2)import
- 引入部分内容
import { name } from './b'
import { name as NameProp } from './b'
- 引入全部内容
import * as info from './b'
(3)export default
一个模块中只能有一个 export default
- 直接导出
export default 'dylan'
(4)export = 和 import xx = require()
TS中特有的形式。
export
、import
属于 ES6规范,require
属于 commonjs 规范,二者是不兼容的。TS为了兼容这两种写法,新增了 export =
和 import xx = require()
这两个语句。
- export =
// b.ts
export = 'dylan';
// index.ts
import name = require('./b');
console.log(name); // dylan
实际使用:moment
npm i moment -D
- 第一种方式:
import moment from 'moment';
console.log(moment)
ƒ hooks() { return hookCallback.apply(null, arguments); }
这种方式返回了一个函数
- 第二种方式
import * as moment from 'moment'
console.log(moment)
{...}
这种方式把 moment
中的所有参数都导出出来了(包括默认导出)。
- 第三种方式
import moment = require('moment');
console.log(moment);
ƒ hooks() { return hookCallback.apply(null, arguments); }
和第一种方式的返回内容一致,都是引用了它的默认导出
2、命名空间
命名空间是有点过时了的概念,一般使用模块就足够了!!!
我们在什么情况下使用命名空间,在什么情况下使用模块呢?
- 命名空间:
- 当我们在程序内部,防止全局污染;想把相关的内容放在一起
- 模块:
- 当我们封装了一个工具或者库,想适用于一个模块系统引入的时候
- 实际上模块也有防止全局污染的作用,所以大多数情况下我们都使用模块
命名空间实际上相当于定义了一个大的对象,里面可以定义变量、类、接口等等。但是如果不使用 export
关键字指定哪些内容对外可见的话,外部是没办法访问到的。
// space.ts
namespace Validation {
const isLetterReg = /^[A-Za-z]+$/;
export const isNumberReg = /^[0-9]+$/;
export const checkLetter = (text: any) => {
return isLetterReg.test(text);
};
}
3、模块解析
(1)相对和非相对模块导入
根据引入模块是相对还是非相对,模块的导入会以不同的方式去解析。
- 相对导入
/
:根目录./
:当前目录../
:上级目录
- 非相对导入
- baseUrl
- 路径映射
- 外部模块
(2)模块解析策略
TS 中有两种模块解析策略可以选择,一个是 node ,一个是 classic。可以通过 tsconfig.json
文件的 moduleResolution
参数进行配置
如果没有配置 moduleResolution
,则 TS 会根据 module
配置项来决定。
- 使用 classic:module = amd、system、es2015等es
- 内容:TS的默认解析策略,也是 ES6 模块系统的解析方式
- 相对导入模块是相对于导入该模块的文件解析的
- 非相对模块导入,编译器会从内向外去一次查找(从我们引入的地方,逐级往外查找)
- 当前模块的 .ts 文件
- .d.ts 文件
- 上级目录 ts => 上级目录 .d.ts 文件
- 使用 node:除上述外的其他情况
- 内容:nodeJS的模块系统解析方式
- 区别在于 nodeJS 主要是查找 .js 文件,而 ts 查找 .ts .tsx .d.ts 三种文件
- nodejs 会查找
package.json
文件,通过main
字段确定我们的入口文件是哪个。ts 则会查找package.json
中的types
字段- .ts
- .tsx
- .d.ts
- 看看 package.json 中的 types 是否为这个模块指定了入口文件
- index.ts
- index.tsx
- index.d.ts
- 如果还没找到,就向上一级,找上一级的 node_modyles 文件,继续上述的顺序
4、模块解析配置项
模块解析配置项都在文件 tsconfig.json 文件中
- baseUrl
baseUrl
在运行的时候要求模块都放在一个文件夹里,这些模块可能来自各个文件夹,构建工具会把它们集中放在一起。通过设置 baseUrl 来告诉编译器去哪儿查找这些被集中在一起的模块。所有相对模块都会被当作相对于 baseUrl。
但是要注意相对模块并不会受 baseUrl
影响,相对模块是根据它的引入模块路径来查找的。可以通过baseUrl
来设置编译之后每个文件都放在哪个文件夹下。
"baseUrl": "."
上面的写法作用:相对于当前跟目录
- paths
用来设置路径映射,有时模块的文件名并不按照默认情况是 模块名 或者 index.ts
。
或者模块文件并不在根文件夹下,比如某些模块是在它的 dist
文件夹下,这时候我们就可以使用 paths
来映射它在哪里。
"paths": {
"jquery": ["node_modules/jquery/dist/jquery"]
}
更常用的方式:为第三方模块编写的声明文件是在哪个文件夹下
"paths": {
"*": ["node_modules/@types", "src/typings"]
}
这样的话,我们的第三方模块就会在这两个地方去查找声明文件。
paths
是相对 baseUrl
的,所以只要我们指定 paths
,就一定要指定 baseUrl
- rootDirs
指定一个路径列表,在构建时编译器会将这个路径列表中的路径内容放在一个文件夹中。
"rootDirs": [
"src/module",
"src/core"
]
这样的话,编译器在构建的时候,会将这两个文件夹的文件复制到输出的同一个目录中。
设置之后,可以在 index.ts
中使用相对路径,来引入一些模块
- noResolve(命令行 tsc)
TS 编译器在编译之前会先解析模块引用,每解析一个 import
模块后这个文件模块就会加入到模块列表。
通过在命令行加上 noResolve
选项来告诉编译器不要将命令行没有指定的模块文件加入到编译文件列表
tsc index.ts ./a.ts --noResolve
我们在 index.ts
中引入了 a.ts
和 b.ts
,但因为我们只在命令行写了 a.ts
,并且加了 noResolve
参数,最后变化的时候就只会把 index.ts
和 a.ts
编译进去。这样的话就会报找不到模块 b 的错误了。
转载自:https://juejin.cn/post/7069933060271276062