当前位置:网站首页>LayaBox---TypeScript---命名空间和模块
LayaBox---TypeScript---命名空间和模块
2022-08-02 10:01:00 【格拉格拉】
目录
1.介绍
我们先来写一段程序并将在整篇文章中都使用这个例子。
所有的验证器都放在一个文件里
interface StringValidator {
isAcceptable(s: string): boolean;
}
let lettersRegexp = /^[A-Za-z]+$/;
let numberRegexp = /^[0-9]+$/;
class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
// Some samples to try
let strings = ["Hello", "98052", "101"];
// Validators to use
let validators: { [s: string]: StringValidator; } = {};
validators["ZIP code"] = new ZipCodeValidator();
validators["Letters only"] = new LettersOnlyValidator();
// Show whether each string passed each validator
for (let s of strings) {
for (let name in validators) {
let isMatch = validators[name].isAcceptable(s);
console.log(`'${ s }' ${ isMatch ? "matches" : "does not match" } '${ name }'.`);
}
}2.命名空间
随着更多验证器的加入,我们需要一种手段来组织代码,以便于在记录它们类型的同时还不用担心与其它对象产生命名冲突。
2.1使用命名空间的验证器
namespace Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
const lettersRegexp = /^[A-Za-z]+$/;
const numberRegexp = /^[0-9]+$/;
export class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
}
// Some samples to try
let strings = ["Hello", "98052", "101"];
// Validators to use
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();
// Show whether each string passed each validator
for (let s of strings) {
for (let name in validators) {
console.log(`"${ s }" - ${ validators[name].isAcceptable(s) ? "matches" : "does not match" } ${ name }`);
}
}3.分离到多文件
当应用变得越来越大时,我们需要将代码分离到不同的文件中以便于维护。
3.1 多文件的命名空间
现在,我们把Validation命名空间分割成多个文件。 尽管是不同的文件,它们仍是同一个命名空间,并且在使用的时候就如同它们在一个文件中定义的一样。 因为不同文件之间存在依赖关系,所以我们加入了引用标签来告诉编译器文件之间的关联。
---------Validation.ts--------------------------------------------
namespace Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
}
------------LettersOnlyValidator.ts-------------------------------
/// <reference path="Validation.ts" />
namespace Validation {
const lettersRegexp = /^[A-Za-z]+$/;
export class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
}
-------------ZipCodeValidator.ts-----------------------------------
/// <reference path="Validation.ts" />
namespace Validation {
const numberRegexp = /^[0-9]+$/;
export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
}
-------------Test.ts------------------------------------------------
/// <reference path="Validation.ts" />
/// <reference path="LettersOnlyValidator.ts" />
/// <reference path="ZipCodeValidator.ts" />
// Some samples to try
let strings = ["Hello", "98052", "101"];
// Validators to use
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();
// Show whether each string passed each validator
for (let s of strings) {
for (let name in validators) {
console.log(`"${ s }" - ${ validators[name].isAcceptable(s) ? "matches" : "does not match" } ${ name }`);
}
}当涉及到多文件时,我们必须确保所有编译后的代码都被加载了。
我们有两种方式。
第一种方式,把所有的输入文件编译为一个输出文件,需要使用--outFile标记:
tsc --outFile sample.js Test.ts
编译器会根据源码里的引用标签自动地对输出进行排序。你也可以单独地指定每个文件。
tsc --outFile sample.js Validation.ts LettersOnlyValidator.ts ZipCodeValidator.ts Test.ts第二种方式,我们可以编译每一个文件(默认方式),那么每个源文件都会对应生成一个JavaScript文件。
然后,在页面上通过 <script>标签把所有生成的JavaScript文件按正确的顺序引进来,
比如:
MyTestPage.html (excerpt)
<script src="Validation.js" type="text/javascript" />
<script src="LettersOnlyValidator.js" type="text/javascript" />
<script src="ZipCodeValidator.js" type="text/javascript" />
<script src="Test.js" type="text/javascript" />4.别名
另一种简化命名空间操作的方法是使用
import q = x.y.z给常用的对象起一个短的名字。 不要与用来加载模块的import x = require('name')语法弄混了,这里的语法是为指定的符号创建一个别名。 你可以用这种方法为任意标识符创建别名,也包括导入的模块中的对象。
namespace Shapes {
export namespace Polygons {
export class Triangle { }
export class Square { }
}
}
import polygons = Shapes.Polygons;
// Same as "new Shapes.Polygons.Square()"
let sq = new polygons.Square();️注意:
1.我们并没有使用
require关键字,而是直接使用导入符号的限定名赋值。2.这与使用
var相似,但它还适用于类型和导入的具有命名空间含义的符号。3.重要的是,对于值来讲,
import会生成与原始符号不同的引用,所以改变别名的var值并不会影响原始变量的值。
5.使用其它的JavaScript库
5.1 外部明明空间
流行的程序库D3在全局对象d3里定义它的功能。 因为这个库通过一个 <script>标签加载(不是通过模块加载器),它的声明文件使用内部模块来定义它的类型。 为了让TypeScript编译器识别它的类型,我们使用外部命名空间声明。
比如:
D3.d.ts (部分摘录)
declare namespace D3 {
export interface Selectors {
select: {
(selector: string): Selection;
(element: EventTarget): Selection;
};
}
export interface Event {
x: number;
y: number;
}
export interface Base extends Selectors {
event: Event;
}
}
declare var d3: D3.Base;6.命名空间和模块
命名空间是位于全局命名空间下的一个普通的带有名字的JavaScript对象。
它们可以在多文件中同时使用,并通过
--outFile结合在一起。 命名空间是帮你组织Web应用不错的方式,你可以把所有依赖都放在HTML页面的<script>标签里。
模块像命名空间一样,可以包含代码和声明。 不同的是模块可以 声明它的依赖。
模块会把依赖添加到模块加载器上(例如CommonJs / Require.js)。模块也提供了更好的代码重用,更强的封闭性以及更好的使用工具进行优化。
7. 命名空间和模块的陷阱
7.1 对模块使用
一个常见的错误是使用/// <reference>引用模块文件,应该使用import。 要理解这之间的区别,我们首先应该弄清编译器是如何根据 import路径(例如,import x from "...";或import x = require("...")里面的...,等等)来定位模块的类型信息的。
编译器首先尝试去查找相应路径下的.ts,.tsx再或者.d.ts。 如果这些文件都找不到,编译器会查找 外部模块声明。 回想一下,它们是在 .d.ts文件里声明的。
------------------------myModules.d.ts---------------------
// In a .d.ts file or .ts file that is not a module:
declare module "SomeModule" {
export function fn(): string;
}
//----------myOtherModule.ts---------------------------------
/// <reference path="myModules.d.ts" />
import * as m from "SomeModule";这里的引用标签指定了外来模块的位置。 这就是一些TypeScript例子中引用 node.d.ts的方法。
7.2 不必要的命名空间
如果你想把命名空间转换为模块,它可能会像下面这个文件一件:
---------------shapes.ts--------------------------------------------
export namespace Shapes {
export class Triangle { /* ... */ }
export class Square { /* ... */ }
}
顶层的模块Shapes包裹了Triangle和Square。 对于使用它的人来说这是令人迷惑和讨厌的:
--------------shapeConsumer.ts-------------------------------------
import * as shapes from "./shapes";
let t = new shapes.Shapes.Triangle(); // shapes.Shapes?不应该对模块使用命名空间,使用命名空间是为了提供逻辑分组和避免命名冲突。 模块文件本身已经是一个逻辑分组,并且它的名字是由导入这个模块的代码指定,所以没有必要为导出的对象增加额外的模块层。
下面是改进的例子:
------------shapes.ts--------------------------
export class Triangle { /* ... */ }
export class Square { /* ... */ }
---------shapeConsumer.ts----------------------
import * as shapes from "./shapes";
let t = new shapes.Triangle();7.3 模块的取舍
就像每个JS文件对应一个模块一样,TypeScript里模块文件与生成的JS文件也是一一对应的。 这会产生一种影响,根据你指定的目标模块系统的不同,你可能无法连接多个模块源文件。 例如当目标模块系统为 commonjs或umd时,无法使用outFile选项,但是在TypeScript 1.8以上的版本能够使用outFile当目标为amd或system。
边栏推荐
猜你喜欢
随机推荐
matlab-day02
Getting Started with SCM from Scratch (1): Summary of Background Knowledge
日元疲软令游戏机在日本变身“理财产品”:黄牛大赚
yolov7 innovation point
STL中list实现
【云原生】快出数量级的性能是怎样炼成的?就提升了亿点点
Shell script realizes multi-select DNS simultaneous batch resolution of domain name IP addresses (new update)
Re22:读论文 HetSANN An Attention-based Graph Neural Network for Heterogeneous Structural Learning
wireshark的安装教程(暖气片安装方法图解)
Chapter 15 Generics
适配器模式适配出栈和队列及优先级队列
你认同这个观点吗?大多数企业的数字化都只是为了缓解焦虑
php组件漏洞
Naive Bayesian Method of Li Hang's "Statistical Learning Methods" Notes
软件测试与质量 之白盒测试
8月份的.NET Conf 活动 专注于 .NET MAUI
The ggbarplot function of the R language ggpubr package visualizes the grouped histogram, sets the add parameter to mean_se to visualize the histogram of the mean values of different levels and adds
iNFTnews | 看见元宇宙的两面,何谓全真互联网和价值互联网?
刷题错题录1-隐式转换与精度丢失
qq邮箱日发5万邮件群发技术(qq邮箱怎样定时发送邮件)









