您的位置:首页 > Web前端 > JavaScript

TypeScript与JavaScript不同之处系列(九) ===> 命名空间, 三斜线指令

2020-04-05 07:15 801 查看

本系列目的: 列出TypeScript与JavaScript的不同点, 缩小文档内容, 提高学习速度. 原文档地址: https://www.tslang.cn/index.html

全系列目录

Symbol, 迭代器和生成器, 模块与原生js重合度太高不整理

文章目录

  • 2. 三斜线指令
  • 1. 命名空间

    1.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);
    }
    }
    
    let strings = ["Hello", "98052", "101"];
    
    let validators: { [s: string]: StringValidator; } = {};
    validators["ZIP code"] = new ZipCodeValidator();
    validators["Letters only"] = new LettersOnlyValidator();
    
    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 }'.`);
    }
    }

    使用关键字

    namespace
    , 用命名空间重写上面代码, 并使用关键字
    export
    暴露出功能

    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);
    }
    }
    }
    
    let strings = ["Hello", "98052", "101"];
    
    // 由于是在命名空间之外访问,因此需要限定类型的名称,比如 Validation.StringValidator
    let validators: { [s: string]: Validation.StringValidator; } = {};
    validators["ZIP code"] = new Validation.ZipCodeValidator();
    validators["Letters only"] = new Validation.LettersOnlyValidator();
    
    for (let s of strings) {
    for (let name in validators) {
    console.log(`"${ s }" - ${ validators[name].isAcceptable(s) ? "matches" : "does not match" } ${ name }`);
    }
    }

    1.2. 分离文件

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

    现在,我们把

    Validation
    命名空间分割成多个文件。 尽管是不同的文件,它们仍是同一个命名空间,并且在使用的时候就如同它们在一个文件中定义的一样。 因为不同文件之间存在依赖关系,所以我们加入了引用标签来告诉编译器文件之间的关联。 我们的测试代码保持不变。

    a.ts文件

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

    b.ts文件

    // 此处为三斜线指令, 文章末尾有介绍
    /// <reference path="a.ts" />
    namespace Validation {
    const lettersRegexp = /^[A-Za-z]+$/;
    export class LettersOnlyValidator implements StringValidator {
    isAcceptable(s: string) {
    return lettersRegexp.test(s);
    }
    }
    }

    c.ts文件

    /// <reference path="a.ts" />
    namespace Validation {
    const numberRegexp = /^[0-9]+$/;
    export class ZipCodeValidator implements StringValidator {
    isAcceptable(s: string) {
    return s.length === 5 && numberRegexp.test(s);
    }
    }
    }

    d.ts文件

    /// <reference path="a.ts" />
    /// <reference path="b.ts" />
    /// <reference path="c.ts" />
    
    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 输出文件名.js 入口文件.ts
    tsc --outFile gkd.js d.ts

    第二种方式,我们可以编译每一个文件(默认方式),那么每个源文件都会对应生成一个

    JavaScript
    文件。 然后,在页面上通过
    <script>
    标签把所有生成的JavaScript文件按正确的顺序引进来,比如:

    <script src="a.js" type="text/javascript" />
    <script src="b.js" type="text/javascript" />
    <script src="c.js" type="text/javascript" />
    <script src="d.js" type="text/javascript" />

    1.3. 别名

    namespace Shapes {
    export namespace Polygons {
    export function gkd ():void {
    num++;
    }
    export let num = 0;
    }
    }
    
    import polygons = Shapes.Polygons;
    let sq = polygons.num; // 等同于 "Shapes.Polygons.num"
    console.log(sq); // 0
    
    polygons.gkd();
    console.log(sq); // 0

    注意: 此import不同于es2015的import, es2015的import拿的是值的引用, 而这里时赋值操作!!!, 从下面编译后的代码中可见一斑

    var Shapes;
    (function (Shapes) {
    var Polygons;
    (function (Polygons) {
    function gkd() {
    Polygons.num++;
    }
    Polygons.gkd = gkd;
    Polygons.num = 0;
    })(Polygons = Shapes.Polygons || (Shapes.Polygons = {}));
    })(Shapes || (Shapes = {}));
    var polygons = Shapes.Polygons; // 赋值操作
    var sq = polygons.num;
    console.log(sq);
    polygons.gkd();
    console.log(sq);

    1.4. 使用其它的JavaScript库

    为了描述不是用TypeScript编写的类库的类型,我们需要声明类库导出的API。 由于大部分程序库只提供少数的顶级对象,命名空间是用来表示它们的一个好办法

    我们称其为声明是因为它不是外部程序的具体实现。 我们通常在

    .d.ts
    里写这些声明。 如果你熟悉C/C++,你可以把它们当做
    .h
    文件

    2. 三斜线指令

    三斜线指令是包含单个XML标签的单行注释。 注释的内容会做为编译器指令使用
    三斜线指令仅可放在包含它的文件的最顶端。 一个三斜线指令的前面只能出现单行或多行注释,这包括其它的三斜线指令。 如果它们出现在一个语句或声明之后,那么它们会被当做普通的单行注释,并且不具有特殊的涵义

    2.1.
    /// <reference path="..." />

    该指令是三斜线指令中最常见的一种。 它用于声明文件间的依赖

    2.2.
    /// <reference types="..." />

    该指令则声明了对某个包的依赖, 对这些包的名字的解析与在 import语句里对模块名的解析类似。 可以简单地把三斜线类型引用指令当做 import声明的包

    例如,把

    /// <reference types="node" />
    引入到声明文件,表明这个文件使用了
    @types/node/index.d.ts
    里面声明的名字; 并且,这个包需要在编译阶段与声明文件一起被包含进来
    仅当在你需要写一个d.ts文件时才使用这个指令

    2.3.
    /// <reference no-default-lib="true"/>

    这个指令把一个文件标记成默认库。 你会在

    lib.d.ts
    文件和它不同的变体的顶端看到这个注释。

    这个指令告诉编译器在编译过程中不要包含这个默认库(比如,

    lib.d.ts
    )。 这与在命令行上使用
    --noLib
    相似。

    还要注意,当传递了

    --skipDefaultLibCheck
    时,编译器只会忽略检查带有
    /// <reference no-default-lib="true"/>
    的文件。

    • 点赞
    • 收藏
    • 分享
    • 文章举报
    刘翾 博客专家 发布了167 篇原创文章 · 获赞 275 · 访问量 59万+ 他的留言板 关注
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: