您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

TypeScript 模块

在没有使用模块化编程的时代,会经常遇到污染、变量重名、多个之间存在依赖关系,需要保证一定加载顺序等问题。在模块化这种规范被提出后,得到社区和广大开发者的积极响应。

本节将介绍 TypeScript 的模块化方案,学习模块的导入导出机制,要注意 TypeScript 是怎么样兼容 CommonJS 和 AMD 规范的。

模块在其自身的作用域里执行,而不是在全局作用域里。

export: 导出模块中的变量、、类、接口等;

import: 导入其他模块导出的变量、、类、接口等。

TypeScript 与 ECMAScript 2015 一样,任何包含顶级 import 或者 export 的都被当成模块。相反的,如果不带有顶级的 import 或者 export 声明,那么它的被视为全局可见的。

在 TypeScript 工程创建 test.ts ,写入:

const a = 

然后,在相同的工程下创建另 test2.ts ,写入:

const a = 

此时编译器会重复定义,虽然是在不同的下,但处于同一全局空间。

如果 export 导出语句:

export const a = 

这样,两个 a 因处于不同的命名空间,就不会报错。

任何声明(比如变量,,类,类型别名或接口)都能够通过 export 关键字来导出。

export.ts:

export const a: number = 
export const add = (x: number, y:number) => x + y 

export interface User {
  nickname: string,
  department: string
}
export class Employee implements User {
  public nickname!: string
  public department!: string
}

export type used = true | false

解释: 每个声明都通过 export 关键字导出。

const a: number = 
const add = (x: number, y:number) => x + y 

interface User {
  nickname: string,
  department: string
}
class Employee implements User {
  public nickname!: string
  public department!: string
}

type used = true | false

export { a, add, Employee }

解释: 先进行声明操作,最终统一使用 export 关键字导出。

const a: number = 
const add = (x: number, y:number) => x + y 

interface User {
  nickname: string,
  department: string
}
class Employee implements User {
  public nickname!: string
  public department!: string
}

type used = true | false

export { add }
export { a as level, used as status, Employee }

解释: 在导出时,可以用 as 关键字将声明。

重新导出并不会在当前模块导入那个模块或定义新的局部变量。

ZipCodeValidator.ts:

export interface StringValidator {
  isAcceptable(s: string): boolean
}

export const numberRegexp = /^[0-9]+$/

class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
  return s.length ===  && numberRegexp.test(s)
}
}
export { ZipCodeValidator }
export { ZipCodeValidator as mainValidator }

ParseIntBasedZipCodeValidator.ts:

export class ParseIntBasedZipCodeValidator {
  isAcceptable(s: string) {
    return s.length ===  && parseInt(s).toString() === s
  }
}

// 导出原先的验证器但做了
export {ZipCodeValidator as RegExpBasedZipCodeValidator} from './ZipCodeValidator'

解释: 在 ParseIntBasedZipCodeValidator.ts 中,重新导出 ZipCodeValidator.ts 中的声明。

或者模块可以包裹多个模块,并把他们导出的联合在一起通过语法:export * from 'module'

比如在 validator.ts 中,统一导出这两个模块。

// validator.ts
export * from './ZipCodeValidator'
export * from './ParseIntBasedZipCodeValidator'
export default class ZipCodeValidator {
  static numberRegexp = /^[0-9]+$/
  isAcceptable(s: string) {
    return s.length ===  && ZipCodeValidator.numberRegexp.test(s)
  }
}

解释: 每个模块都可以有 default 导出,且模块只能够有 default 导出。

使用 import 形式来导入其它模块中的导出。

import { a, add, Employee } from './export'
import { a as level, used as status } from './export'

将整个模块导入到变量,并通过它来访问模块的导出部分

import * as TYPES from './export'
import './export'

CommonJS 和 AMD 的环境里都有 exports 变量,这个变量包含了模块的所有导出。

CommonJS 和 AMD 的 exports 都可以被赋值为 对象, 这种情况下其作用就类似于 EcmaScript 2015 语法里的认导出,即 export default 语法了。虽然作用相似,但是 export default 语法并不能兼容 CommonJS 和 AMD 的 exports

为了 CommonJS 和 AMD 的 exports, TypeScript 提供了 export = 语法。

export = 语法定义模块的导出 对象。 这里的 对象 一词指的是类,接口,命名空间,或枚举

若使用 export = 导出模块,则必须使用 TypeScript 的特定语法 import module = require('module') 来导入此模块。

ZipCodeValidator.ts:

let numberRegexp = /^[0-9]+$/
class ZipCodeValidator {
  isAcceptable(s: string) {
    return s.length ===  && numberRegexp.test(s)
  }
}
export = ZipCodeValidator

解释: 使用 export = 语法导出类对象。

Test.ts:

import Zip = require('./ZipCodeValidator')

// Some samples to try
let strings = ['Hello', '98052', '101']

// Validators to use
let validator = new Zip()

// Show whether each string passed each validator
strings.forEach(s => {
  console.log(`'${ s }' - ${ validator.isAcceptable(s) ? 'matches' : 'does not match' }`)
});

解释: 通过 import = require() 形式导入。

可以看到 TypeScript 的模块机制基本采用的是 ES6 的内置模块化机制,另外了 export = 形式来兼容 AMD 与 CommonJS 规范。


联系我
置顶