TypeScript 学习笔记8: Modules
来源:互联网 发布:js时间控件webdriver 编辑:程序博客网 时间:2024/06/09 07:39
原文链接:https://leanpub.com/essentialtypescript/read#leanpub-auto-modules
TypeScript支持两种模块:内部模块、外部模块。 内部模块就是用 namespace 封装起来的代码块。外部模块就是CommonJS、amd等实现的功能,在TypeScript中定义了更简单的语法。
1. Namespaces
namespace 也是 syntactic sugar, 本质上它也是用 function 定义作用域,《Eloquent JavaScript》的第十章详细的讲了基本原理。直接看用法:
//Model.tsnamespace TodoApp.Model { export interface Todo { id: number; name: string; state: TodoState; }}namespace TodoApp.Model { export enum TodoState { New = 1, Active = 2, Complete = 3, Deleted = 4 }}namespace TodoApp.DataAccess { import Todo = TodoApp.Model.Todo; export interface ITodoService { add(todo: Todo): Todo; delete(todoId: number): void; getAll(): Todo[]; getById(todoId: number): Todo; }}
说明:
1. namespace 定义一个作用域,和全局空间隔离开来;
2. namespace 的名字 TodoApp.Model,中间有没有“点”都可以,有多少“点”都可以;
3. 一个namespace可以拆分成多个定义,如上面的TodoApp.Model,这不会导致重复定义;它们也可以写在不同的文件中;
4. 多个namespace的定义可以写在一个文件中;
5. 加上 export 前缀,才能在其它namespace中访问,否则,出了它所在的namespace空间,谁也不认识它。如:interface Todo, enum TodoState。
6. 在其它namespace中使用TodoApp.Model.Todo需要写全名,或则,定义别名:import Todo = TodoApp.Model.Todo;
我觉得 import 这个关键字不好,用 alias 会更明确,因为,这里并没有import的作用,只是给 TodoApp.Model.Todo 一个别名。
2. Using namespaces to encapsulate private members
回顾一下前两章讲的 class TodoService,它用到了 static 变量和方法创建新的TodoId,本质上来讲,用 static 方法把 nextId() 方法放到 TodoService 这个类的定义中,是为了把这个功能全局空间分离出来,现在,有了namespace,我们可以这么做:
//DataAccess.tsnamespace DataAccess { import Model = TodoApp.Model; import Todo = Model.Todo; export interface ITodoService { add(todo: Todo): Todo; delete(todoId: number): void; getAll(): Todo[]; getById(todoId: number): Todo; } let _lastId: number = 0; function generateTodoId(): number { return _lastId += 1; } class TodoService implements ITodoService { constructor(private todos: Todo[]) { } add(todo: Todo) { todo.id = generateTodoId(); this.todos.push(todo); return todo; } // ... }}
把 _lastId 和 generateTodoId() 从TodoService 中拿出来,放到 namespace DataAccess 定义的局部空间中。
3. Internal and External Modules
Internal Module:namespace,上一节介绍的方式;
External Module:每个module在自己的文件中,不使用namespace,文件本身就定义了一个局部空间。TypeScript 提供了一种方式,ECMAScript2015也提供了一种方式。无论用哪一种方式,tsc 编译出来的代码是相同的。
4. Switching from internal to external modules
- 去掉Model.ts 和 DataAccess.ts 文件中的namespace关键字,及其相关的括号;
修改 tsconfig.json,指定 module 属性:
{ "compilerOptions": { "target": "es5", "module": "system" }}
module属性有多个备选值:system, amd, commonjs, es2015 等等。
5. Importing modules using Require syntax
//Model.tsexport interface Todo { id: number; name: string; state: TodoState;} export enum TodoState { New = 1, Active = 2, Complete = 3, Deleted = 4}
//DataAccess.tsimport Model = require('./Model');import Todo = Model.Todo;// 其它代码 ...
说明:
1. Model.ts 是一个文件,也是一个module;
2. Model.ts 中不需要namespace;
3. 每一个需要暴露给外部的接口,都需要加上 export 前缀,如:export interface Todo 和 export enum TodoState
4. DataAccess.ts 中,require(‘./Model’) 导入了Model.ts 模块,不要写文件扩展名;
5. import Model = … ,只是给这个模块定义一个别名(alias),不是必须叫Model,可以是任意名字;
6. Importing modules using ECMAScript 2015 syntax
//DataAccess.tsimport * as Model from './Model';import Todo = Model.Todo;// 其它代码 ...
这是es2015 导入模块的语法,只有一行代码不同。
事实上,es2015的导入语法还提供了更丰富的内容。
1. 只导入Todo:
import {Todo} from './Model';
这时,后续的代码不能使用 TodoState。
2. 导入指定内容:
import {Todo, TodoState} from './Model';
导入Todo 和 TodoState,如果Model.ts中还有其它export,不会导入。
3. 导入的同时,指定别名:
import {Todo as TodoTask, TodoState} from './Model';
给Todo指定了一个别名:TodoTask,后续的代码用到Todo时,都要改成TodoTask。
4. 导入模块,但导入它任何 export 的接口
import './Config';
通常很少用到这种方式。当Config.ts模块中有自动执行的代码,这种方式才有用,例如:Config.ts 中有一段代码,用来配置环境变量,而这些代码在加载时就会自动执行。
7. Loading External Modules
ECMAScript 2015 虽然定义了加载模块的语法,但现在还没有一个标准的loader,浏览器并没有内置支持这种语法的loader。多年以来,已经有多个loader被广泛使用,我们必须从中选择一个。我们选择 systemJS 作为模块加载器,因为,它提供了 es2015 的导入模块的语法。这样的话,等将来es2015的load语法被浏览器广泛支持时,我们不用修改代码,就可以使用内置的loader了。
需要在 index.html 中加载 system.js:
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.22/system.js"></script>
当然,我们也可以把system.js下载到本地。
使用System 引用 app.ts:
<script type="text/javascript"> System.defaultJSExtensions = true; System.import('app')</script>
这样,当加载index.html 时,app.ts 中的代码就开始执行了。
在app.ts中添加一些代码:
// app.tsimport { Todo, TodoState } from './Model'; import { TodoService } from './DataAccess';let service = new TodoService([]);service.add({ id: 1, name: 'Pick up drycleaning', state: TodoState.New})let todos = service.getAll();todos.forEach(todo => console.log(`${todo.name} [${TodoState[todo.state]}]`))
到命令行下,运行:
cd TypeScriptTodo
lite-server
看看浏览器 console 的输出。
- TypeScript 学习笔记8: Modules
- Typescript Modules
- TypeScript 学习笔记
- TypeScript 学习笔记1
- TypeScript 学习笔记2
- TYPESCRIPT 学习笔记3
- TypeScript学习笔记一
- TypeScript 学习笔记
- Typescript学习笔记
- TypeScript学习笔记
- TypeScript学习笔记一
- AngularJs学习笔记--Modules
- TypeScript学习笔记之 类
- TypeScript学习笔记之函数
- TypeScript学习笔记之 泛型
- TypeScript 学习笔记1: 简介
- TypeScript 学习笔记6: Classes
- TypeScript 学习笔记7: Generics
- 两种分布式锁实现方案(一)
- CSS position 属性分析
- 关于树状数组的姿势
- Django-数据库常用类型与关键字
- JDBC知识
- TypeScript 学习笔记8: Modules
- 白话空间统计二十四:地理加权回归(十)完结篇
- Linux常用指令
- 基本IO操作 、 文本数据IO操作
- ssm集成框架freemarker
- C++前途
- CardView学习笔记
- 【Linux基础】用10条命令查看系统性能
- error LNK2019: 无法解析的外部符号