/blog/
/blog/one/
/blog/resume/
/blog/answer/
/blog/code/
/blog/know/
/blog/posts/1109. 航班预订统计/
/blog/posts/1143. 最长公共子序列/
/blog/posts/1221. 分割平衡字符串/
/blog/posts/1436. 旅行终点站/
/blog/posts/1480. 一维数组的动态和/
/blog/posts/1588. 所有奇数长度子数组的和/
/blog/posts/162. 寻找峰值/
/blog/posts/1646. 获取生成数组中的最大值/
/blog/posts/165. 比较版本号/
/blog/posts/166. 分数到小数/
/blog/posts/187. 重复的DNA序列/
/blog/posts/1894. 找到需要补充粉笔的学生编号/
/blog/posts/208. 实现 Trie (前缀树)/
/blog/posts/211. 添加与搜索单词 - 数据结构设计/
/blog/posts/212. 单词搜索 II/
/blog/posts/223. 矩形面积/
/blog/posts/229. 求众数 II/
/blog/posts/230. 二叉搜索树中第K小的元素/
/blog/posts/240. 搜索二维矩阵 II/
/blog/posts/260. 只出现一次的数字 III/
/blog/posts/273. 整数转换英文表示/
/blog/posts/282. 给表达式添加运算符/
/blog/posts/284. 顶端迭代器/
/blog/posts/292. Nim 游戏/
/blog/posts/299. 猜数字游戏/
/blog/posts/301. 删除无效的括号/
/blog/posts/326. 3的幂/
/blog/posts/335. 路径交叉/
/blog/posts/352. 将数据流变为多个不相交区间/
/blog/posts/36. 有效的数独/
/blog/posts/371. 两整数之和/
/blog/posts/38. 外观数列/
/blog/posts/407. 接雨水 II/
/blog/posts/405. 数字转换为十六进制数/
/blog/posts/430. 扁平化多级双向链表/
/blog/posts/437. 路径总和 III/
/blog/posts/447. 回旋镖的数量/
/blog/posts/453. 最小操作次数使数组元素相等/
/blog/posts/470. 用 Rand7() 实现 Rand10()/
/blog/posts/476. 数字的补数/
/blog/posts/502. IPO/
/blog/posts/517. 超级洗衣机/
/blog/posts/524. 通过删除字母匹配到字典里最长单词/
/blog/posts/528. 按权重随机选择/
/blog/posts/600. 不含连续1的非负整数/
/blog/posts/639. 解码方法 II/
/blog/posts/66. 加一/
/blog/posts/678. 有效的括号字符串/
/blog/posts/68. 文本左右对齐/
/blog/posts/704. 二分查找/
/blog/posts/725. 分隔链表/
/blog/posts/789. 逃脱阻碍者/
/blog/posts/787. K 站中转内最便宜的航班/
/blog/posts/869. 重新排序得到 2 的幂/
/blog/posts/881. 救生艇/
/blog/posts/797. 所有可能的路径/
/blog/posts/
/blog/posts/剑指 Offer 10- I. 斐波那契数列/
/blog/posts/剑指 Offer 22. 链表中倒数第k个节点/
/blog/posts/面试题 17.14. 最小K个数/
/blog/workshop/
/blog/answer/common/
/blog/answer/interview/
/blog/answer/invest/
/blog/answer/webRTC/01-前置知识/
/blog/answer/webRTC/02-RTCPeerConnection/
/blog/answer/webRTC/03-实践/
/blog/answer/webRTC/
/blog/code/lodash/01/
/blog/code/lodash/
/blog/code/nuxt/
/blog/code/npm/01-pify/
/blog/code/npm/02-downlaod/
/blog/code/npm/03-video.js/
/blog/code/npm/04-craco/
/blog/code/npm/05-axios/
/blog/code/npm/
/blog/code/opensource/01-第一期/
/blog/code/opensource/02-第二期/
/blog/code/opensource/04-第四期/
/blog/code/opensource/05-第五期/
/blog/code/opensource/07-第七期/
/blog/code/opensource/08-第八期/
/blog/code/opensource/09-第九期/
/blog/code/opensource/10-第十期/
/blog/code/opensource/11-第十一期 玩具vite/
/blog/code/opensource/12-第十二期 ni/
/blog/code/opensource/13-第十三期 open/
/blog/code/opensource/14-第十四期 promisify/
/blog/code/opensource/15-第十五期 element新增组件功能/
/blog/code/opensource/16-第十六期 一行代码统一规范 包管理器/
/blog/code/opensource/17-第十七期 js-cookie/
/blog/code/opensource/18-第十八期 delay/
/blog/code/opensource/21-第未知期/
/blog/code/opensource/
/blog/code/react/
/blog/code/vitepress/
/blog/know/back/
/blog/know/computer/
/blog/know/front/
/blog/know/javascript/
/blog/know/network/01-网路/
/blog/know/network/
/blog/know/tool/
/blog/know/typescript/
/blog/workshop/cli/01-项目创建/
/blog/workshop/cli/02-npm包发布/
/blog/workshop/cli/
/blog/workshop/windows11/
/blog/answer/common/business/vuepress搭建之旅/
/blog/answer/common/business/编写代码之前的思考/
/blog/answer/common/offer/03. 数组中重复的数字/
/blog/answer/common/interview/
/blog/answer/common/offer/04. 二维数组中的查找/
/blog/answer/common/offer/05. 替换空格/
/blog/answer/common/offer/07. 重建二叉树/
/blog/answer/common/offer/06. 从尾到头打印链表/
/blog/answer/common/offer/09. 用两个栈实现队列/
/blog/answer/common/offer/10- I. 斐波那契数列/
/blog/answer/common/offer/10- II. 青蛙跳台阶问题/
/blog/answer/common/offer/11. 旋转数组的最小数字/
/blog/answer/common/offer/
/blog/answer/common/offer/剑指 Offer 10- I. 斐波那契数列/
/blog/answer/common/offer/剑指 Offer II 069. 山峰数组的顶部/
/blog/answer/common/web/
/blog/answer/common/offer/剑指 Offer 22. 链表中倒数第k个节点/
/blog/answer/common/web/拖拽/
/blog/answer/common/web/类型判断/
/blog/answer/invest/book/
/blog/answer/invest/book/不可不知的经济真相/
/blog/answer/invest/book/投资第一课/
/blog/answer/invest/book/纳瓦尔宝典/
/blog/answer/interview/basic/01-html/
/blog/answer/interview/basic/02-css/
/blog/answer/interview/basic/03-javascript/
/blog/answer/interview/basic/
/blog/answer/interview/basic/vue/
/blog/code/react/react/
/blog/answer/webRTC/janus/01-init/
/blog/answer/webRTC/janus/03-attach/
/blog/answer/webRTC/janus/
/blog/code/react/redux/
/blog/code/react/router/01-环境设置/
/blog/answer/webRTC/janus/02-janus/
/blog/code/react/router/
/blog/know/back/Egg/01-基础/
/blog/know/back/Egg/egg兼容mysql和mogodb/
/blog/know/back/Egg/
/blog/know/back/nodejs/01-install/
/blog/know/back/nodejs/98-process/
/blog/know/back/nodejs/99-file/
/blog/know/back/nodejs/
/blog/know/computer/algorithm/01-多选投票算法/
/blog/know/computer/algorithm/02-二叉树的各种遍历/
/blog/know/computer/algorithm/03-位运算/
/blog/know/computer/algorithm/04-距离相关/
/blog/know/computer/algorithm/06-线性表/
/blog/know/computer/algorithm/05-字符串/
/blog/know/computer/algorithm/07-队列/
/blog/know/computer/algorithm/08-栈/
/blog/know/computer/algorithm/09-哈希表/
/blog/know/computer/algorithm/10-dfs/
/blog/know/computer/algorithm/11-bfs/
/blog/know/computer/algorithm/
/blog/know/computer/data/01-队列/
/blog/know/computer/data/03-链表/
/blog/know/computer/data/04-树/
/blog/know/computer/data/05-栈/
/blog/know/computer/data/06-其他/
/blog/know/computer/data/06-堆/
/blog/know/computer/data/
/blog/know/computer/dayOne/1011. 在 D 天内送达包裹的能力/
/blog/know/computer/dayOne/1310. 子数组异或查询/
/blog/know/computer/dayOne/137. 只出现一次的数字 II/
/blog/know/computer/dayOne/1473. 粉刷房子 III/
/blog/know/computer/dayOne/1482. 制作 m 束花所需的最少天数/
/blog/know/computer/dayOne/1486. 数组异或操作/
/blog/know/computer/dayOne/1720. 解码异或后的数组/
/blog/know/computer/dayOne/1723. 完成所有工作的最短时间/
/blog/know/computer/dayOne/1734. 解码异或后的排列/
/blog/know/computer/dayOne/554. 砖墙/
/blog/know/computer/dayOne/633. 平方数之和/
/blog/know/computer/dayOne/690. 员工的重要性/
/blog/know/computer/dayOne/7. 整数反转/
/blog/know/computer/dayOne/403. 青蛙过河/
/blog/know/computer/dayOne/740. 删除并获得点数/
/blog/know/computer/dayOne/872. 叶子相似的树/
/blog/know/computer/dayOne/938. 二叉搜索树的范围和/
/blog/know/computer/dayOne/
/blog/know/computer/network/01-网路协议/
/blog/know/computer/network/98-关于options请求/
/blog/know/computer/network/
/blog/know/engineering/babel/
/blog/know/engineering/npm/78-npm push/
/blog/know/engineering/npm/
/blog/know/engineering/react/01-简介/
/blog/know/engineering/react/03-react-router/
/blog/know/engineering/react/04-hooks/
/blog/know/engineering/react/
/blog/know/engineering/webpack/01-基础/
/blog/know/engineering/webpack/02-loader/
/blog/know/engineering/webpack/03-plugin/
/blog/know/engineering/webpack/
/blog/know/front/css/01-选择器/
/blog/know/front/css/02-盒模型/
/blog/know/front/css/03-布局/
/blog/know/front/css/04-文本属性/
/blog/know/front/css/
/blog/know/front/network/01-网路/
/blog/know/front/network/
/blog/know/front/html/01-head/
/blog/know/front/html/02-body/
/blog/know/front/html/09-canvas/
/blog/know/front/html/10-svg/
/blog/know/front/html/
/blog/know/front/react/01-xx/
/blog/know/front/react/02-props/
/blog/know/front/react/03-state/
/blog/know/front/react/04-Lifecycle/
/blog/know/front/react/05-hook/
/blog/know/front/react/06-redux/
/blog/know/front/react/
/blog/know/front/webRTC/
/blog/know/front/webpack/01-基础/
/blog/know/front/webpack/02-loader/
/blog/know/front/webpack/03-plugin/
/blog/know/front/webpack/
/blog/know/javascript/BOM和DOM/01-navigator/
/blog/know/javascript/BOM和DOM/
/blog/know/javascript/advance/07-迭代器与生成器/
/blog/know/javascript/advance/11-promise/
/blog/know/javascript/advance/12-正则表达式/
/blog/know/javascript/advance/
/blog/know/javascript/basic/02-类/
/blog/know/javascript/basic/03-数据类型/
/blog/know/javascript/basic/04-函数进阶/
/blog/know/javascript/basic/
/blog/know/javascript/api/99-promise/
/blog/know/javascript/basic/01-语言基础/
/blog/know/javascript/basic/05-原型链/
/blog/know/tool/chromedevtools/
/blog/know/tool/git/01-基础/
/blog/know/tool/git/02-log/
/blog/know/tool/git/03-checkout/
/blog/know/tool/git/09-submodule/
/blog/know/tool/git/04-diff/
/blog/know/tool/git/10-workflow/
/blog/know/tool/git/
/blog/know/tool/vscode/
/blog/know/typescript/basic/01-基础概念/
/blog/know/typescript/basic/02-基础类型/
/blog/know/typescript/basic/03-接口/
/blog/know/typescript/basic/04-类/
/blog/know/typescript/basic/05-函数/
/blog/know/typescript/basic/06-泛型/
/blog/know/typescript/basic/07-枚举/
/blog/know/typescript/basic/08-高级类型/
/blog/know/typescript/basic/09-模块/
/blog/know/typescript/basic/10-模块解析/
/blog/know/typescript/basic/11-命名空间/
/blog/know/typescript/basic/
/blog/know/typescript/declarationfiles/01-示例/
/blog/know/typescript/declarationfiles/02-结构/
/blog/know/typescript/declarationfiles/03-模板/
/blog/know/typescript/declarationfiles/04-最佳实践/
/blog/know/typescript/declarationfiles/05-深入/
/blog/know/typescript/declarationfiles/

命名空间

关于术语的一点说明: 请务必注意一点,TypeScript 1.5里术语名已经发生了变化。 “内部模块”现在称做“命名空间”。 “外部模块”现在则简称为“模块”,这是为了与ECMAScript 2015里的术语保持一致,(也就是说 module X { 相当于现在推荐的写法 namespace X {)。

第一步

我们先来写一段程序并将在整篇文章中都使用这个例子。 我们定义几个简单的字符串验证器,假设你会使用它们来验证表单里的用户输入或验证外部数据。

所有的验证器都放在一个文件里

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 }'.`);
    }
}

命名空间

随着更多验证器的加入,我们需要一种手段来组织代码,以便于在记录它们类型的同时还不用担心与其它对象产生命名冲突。 因此,我们把验证器包裹到一个命名空间内,而不是把它们放在全局命名空间下。

下面的例子里,把所有与验证器相关的类型都放到一个叫做Validation的命名空间里。 因为我们想让这些接口和类在命名空间之外也是可访问的,所以需要使用export。 相反的,变量lettersRegexpnumberRegexp是实现的细节,不需要导出,因此它们在命名空间外是不能访问的。 在文件末尾的测试代码里,由于是在命名空间之外访问,因此需要限定类型的名称,比如Validation.LettersOnlyValidator

使用命名空间的验证器

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 }`);
    }
}

分离到多文件

当应用变得越来越大时,我们需要将代码分离到不同的文件中以便于维护。

多文件中的命名空间

现在,我们把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" />

别名

另一种简化命名空间操作的方法是使用import q = x.y.z给常用的对象起一个短的名字。 不要与用来加载模块的import x = require('name')语法弄混了,这里的语法是为指定的符号创建一个别名。 你可以用这种方法为任意标识符创建别名,也包括导入的模块中的对象。

namespace Shapes {
    export namespace Polygons {
        export class Triangle { }
        export class Square { }
    }
}

import polygons = Shapes.Polygons;
let sq = new polygons.Square(); // Same as "new Shapes.Polygons.Square()"

注意,我们并没有使用require关键字,而是直接使用导入符号的限定名赋值。 这与使用var相似,但它还适用于类型和导入的具有命名空间含义的符号。 重要的是,对于值来讲,import会生成与原始符号不同的引用,所以改变别名的var值并不会影响原始变量的值。