TS三斜线指令

8,744次阅读
没有评论

共计 2884 个字符,预计需要花费 8 分钟才能阅读完成。

  1. 三斜线指令用主要用于声明文件 & 文件 (/// )、文件 & 第三方模块(/// ) 之间的依赖关系
  2. 三斜线指令 最好只 出现在你手动编写声明文件 (即.d.ts 文件) 的场景
  3. /// 还有用于控制输出文件内容顺序的作用
  4. 三斜线指令的引用路径是相对于包含它的文件的
  5. 三斜线指令出现在非声明文件的情况
    1. 同 namespace 一起出现:用于控制输出文件内容顺序,链接
    2. 同外部模块声明 (Ambient Module Declarations) 一起出现,告诉编译器当前文件对该模块存在依赖关系,并在文件内引入模块的类型声明以便使用,不过当该模块类型声明文件被 tsconfig.json 已经引入时,这时三斜线指令不是必须的,链接

前置知识

  1. tsconfig.json中有一项配置outFile,该配置用于将所有的输出文件整合成一个文件
    在本例中,该项值设定为./result.js,ts 文件编译后的内容将整合于该单一文件中
  2. 三斜线的路径解析策略:解析策略同模块解析策略,其有两种:ClassicNode,可以通过配置 tsconfig.json 中的 moduleResolution 选项值为ClassicNode 来选择解析策略

问题

我们现有如下代码

// nameC.ts
namespace Validation {
  export interface StringValidator {
    isAcceptable(s: string): boolean;
  }
}

// nameB.ts
namespace Validation {
  const lettersRegexp = /^[A-Za-z]+$/;
  export class LettersOnlyValidator implements StringValidator {
    isAcceptable(s: string) {
      return lettersRegexp.test(s);
    }
  }
}

// nameA.ts
let sv: Validation.StringValidator = {
  isAcceptable(s) {
    return true;
  },
};
let lov: Validation.LettersOnlyValidator =
  new Validation.LettersOnlyValidator();
console.log({sv, lov});

在我们使用 tsc 进行编译过后,得到的结果如下

// result.js
"use strict";
let sv = {
  isAcceptable(s) {
    return true;
  },
};
let lov = new Validation.LettersOnlyValidator();
console.log({sv, lov});
var Validation;
(function (Validation) {
  const lettersRegexp = /^[A-Za-z]+$/;
  class LettersOnlyValidator {
    isAcceptable(s) {
      return lettersRegexp.test(s);
    }
  }
  Validation.LettersOnlyValidator = LettersOnlyValidator;
})(Validation || (Validation = {}));

我们运行该 js 文件,发现报错:

`Class ‘LettersOnlyValidator’ used before its declaration.`

我们发现,类 LettersOnlyValidator 在其被定义前就已经使用了,这说明了一个问题
输出文件内容的顺序不对,我们发现 nameA.ts 文件的内容先被解析了,这是不符合我们预期的!

解决办法

ts 为我们提供了三斜线指令 /// 来让我们指定文件解析的先后顺序

我们将 ts 文件内容添加上三斜线指令之后,内容如下

// nameC.ts
namespace Validation {
  export interface StringValidator {
    isAcceptable(s: string): boolean;
  }
}

// nameB.ts
/// 
namespace Validation {
  const lettersRegexp = /^[A-Za-z]+$/;
  export class LettersOnlyValidator implements StringValidator {
    isAcceptable(s: string) {
      return lettersRegexp.test(s);
    }
  }
}

// nameA.ts
/// 
/// 
let sv: Validation.StringValidator = {
  isAcceptable(s) {
    return true;
  },
};

let lov: Validation.LettersOnlyValidator =
  new Validation.LettersOnlyValidator();

console.log({sv, lov});

当文件内使用到了另一个文件内命名空间的内容时,需要在该文件内使用三斜线指令
来告诉编译器你引用的内容所在的位置,后继编译器就会根据三斜线指令的引用关系,
来决定整合文件的内容的顺序

编译后结果如下

// result.js
"use strict";
/// 
var Validation;
/// 
(function (Validation) {
  const lettersRegexp = /^[A-Za-z]+$/;
  class LettersOnlyValidator {
    isAcceptable(s) {
      return lettersRegexp.test(s);
    }
  }
  Validation.LettersOnlyValidator = LettersOnlyValidator;
})(Validation || (Validation = {}));
/// 
/// 
let sv = {
  isAcceptable(s) {
    return true;
  },
};
let lov = new Validation.LettersOnlyValidator();
console.log({sv, lov});

运行 result.js 文件,发现能够正常运行并输出期望结果

原理

编译器在编译文件时有个步骤——预处理输入文件,该步骤会对输入文件预处理来解析所有三斜线指令,在这个过程中额外的文件会被加入到编译过程中。
以上述代码为例,编译器在解析 nameA.ts 文件前,会先监测其文件内容有没有三斜线指令,结果发现有

/// 
/// 

那么编译器会先去对 nameC.ts 进行编译,发现 nameC.ts 中没有三斜线指令,则先将编译结果添加到输出文件中,后面继续解析 nameB.ts
发现 nameB.ts 也使用三斜线指令指向了 nameA.ts,不过其之前已经编译过,就不再处理,而是将 nameB.ts 内容编译后添加到输出文件中,
此时 nameC.ts 的三斜线指令已经预处理完毕,那么就将 nameC.ts 内容编译后添加到输出文件中,此时输出文件的内容便是我们预期的输出结果。

说大白话就是,/// 就是告诉编译器:我这里使用了 nameC.ts 的内容,请你先去编译 nameC.ts 的内容后再来我这

如果有帮到您的话,请点个赞吧~ 谢谢!

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-09-23发表,共计2884字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)