likes
comments
collection
share

TS从入门到放弃【十六】:模块和命名空间

作者站长头像
站长
· 阅读数 26

TS 和 ES6 保持一种,包含顶级的 importexport 的文件都被当作成一个模块,模块中定义的内容仅模块内可见,而不是全局可见。

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中特有的形式。

exportimport 属于 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.tsb.ts,但因为我们只在命令行写了 a.ts,并且加了 noResolve 参数,最后变化的时候就只会把 index.tsa.ts 编译进去。这样的话就会报找不到模块 b 的错误了。