参考: Native ECMAScript 2015 +
代码组织,分拆,管理
模块在其自身的作用域里执行,而不是在全局作用域里;因此模块里的变量,函数,类等等在模块外部是不可见的,
除非你明确地使用export形式之一导出它们。
相反,如果想使用其它模块导出的变量,函数,类,接口等的时候,你必须 import 去获取该文件的 export。
任何包含顶级import或者export的文件都被当成一个模块, 两个模块之间的关系是通过在文件级别上使用imports和exports建立的。
// 声明
export interface StringValidator {
isAcceptable(s: string): boolean;
}
export const numberRegexp = /^[0-9]+$/;
export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string): boolean { return true; };
}
// 重命名导出
export {
numberRegexp as nReg
};
// error
// export {
// name: '',
// age: 10
// }
// 重新导出
export * from '../xx'
export default $;
注意: 如果你是用 deno 执行 TS 文件,import 需要明确指定文件后缀,import xx.ts
。
export const ZipCodeValidator = { /* ... */ };
import { ZipCodeValidator } from "./ZipCodeValidator";
// as
import { ZipCodeValidator as zv } from "./ZipCodeValidator";
// or
import * as zcv "./ZipCodeValidator";
zcv.ZipCodeValidator // ...
// 不关注导出: 一些模块会设置一些全局状态供其它模块使用
import "./commonInit";
// 导入默认导出
// export default $;
import $ from 'jquery';
import 没有强制位置, 一个在编译阶段处理,一个是执行阶段代码。可以理解为变量提升。
console.log(PI); // 3.1415....
import {PI} from './module_export.1.ts'
已经编译到同目录下的 ./build/
中了。
eg: export =
and import fs = require('fs')
CommonJS和AMD都有一个exports对象的概念, 但和 TS 的模块并不相互兼容。 TypeScript模块支持 export =
语法以支持传统的CommonJS和AMD的工作流模型。
可以使用 –module 编译到不同规范看 TS 的模块对于到不同规范的情况。
对于Node.js来说,使用–module commonjs; 对于Require.js来说,使用–module amd tsc --module commonjs xxx
// file a.ts
export const PI = Math.PI;
// const PI = Math.PI;
// export = PI;
// file b.ts
// import PI from './module_export.1.ts';
import exObj = require('./module_export.1.ts');
console.log(exObj.PI);
注意:
条件加载模块
先看看一些 TS 编译相关的实现:
这种模式的核心是 import id = require("...")
语句可以让我们访问模块导出的类型。 模块加载器会被动态调用(通过 require),就像下面if代码块里那样。 它利用了省略引用的优化,所以模块只在被需要时加载。 为了让这个模块工作,一定要注意 import定义的标识符只能在表示类型处使用(不能在会转换成JavaScript的地方)。
为了确保类型安全性,我们可以使用typeof关键字。 typeof关键字,当在表示类型的地方使用时,会得出一个类型值,这里就表示模块的类型。
// TODO 1. 可选的模块加载和其它高级加载场景, 2. 使用其它的JavaScript库
// Consumer.ts import { SomeType, someFunc } from “./MyThings”; let x = new SomeType();
4. 导出模块的同时不要重叠使用命名空间
5. 批量导入
```typescript
// MyThings.ts
export class Dog { ... }
export class Cat { ... }
export class Tree { ... }
export class Flower { ... }
// Consumer.ts
import * as myLargeModule from "./MyLargeModule.ts";
类似高阶函数,高阶组件的处理方案: 你可能经常需要去扩展一个模块的功能。 JS里常用的一个模式是JQuery那样去扩展原对象。 如我们之前提到的,模块不会像全局命名空间对象那样去 合并。 推荐的方案是 不要去改变原来的对象,而是导出一个新的实体来提供新的功能。
方法实践上: 使用 extend 去扩展一个子类是最佳实践,分模块可以实现开闭。但是情分清: is A 和 has A。
这是个恒久话题,继承很好用,但是同回调一样不能乱用,典型的例子是: 企鹅不该直接派生自可飞行的鸟类。