TS三斜线指令
要点
- 三斜线指令用主要用于声明文件&文件(
/// <reference path/>
)、文件&第三方模块(/// <reference types/>
)之间的依赖关系 - 三斜线指令最好只出现在你手动编写声明文件(即.d.ts文件)的场景
/// <reference path/>
还有用于控制输出文件内容顺序的作用- 三斜线指令的引用路径是相对于包含它的文件的
- 三斜线指令出现在非声明文件的情况
三斜线指令 /// <reference path/>
控制输出文件内容顺序原理
前置知识
tsconfig.json
中有一项配置outFile
,该配置用于将所有的输出文件整合成一个文件 在本例中,该项值设定为./result.js
,ts 文件编译后的内容将整合于该单一文件中- 三斜线的路径解析策略:解析策略同模块解析策略,其有两种:
Classic
和Node
,可以通过配置tsconfig.json
中的moduleResolution
选项值为Classic
或Node
来选择解析策略
问题
我们现有如下代码
// 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 文件,发现报错:
我们发现,类LettersOnlyValidator
在其被定义前就已经使用了,这说明了一个问题
输出文件内容的顺序不对,我们发现nameA.ts文件的内容先被解析了,这是不符合我们预期的!
解决办法
ts为我们提供了三斜线指令 /// <reference path='path'>
来让我们指定文件解析的先后顺序
我们将ts文件内容添加上三斜线指令之后,内容如下
// nameC.ts
namespace Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
}
// nameB.ts
/// <reference path='nameC.ts' />
namespace Validation {
const lettersRegexp = /^[A-Za-z]+$/;
export class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
}
// nameA.ts
/// <reference path='nameC.ts' />
/// <reference path='nameB.ts' />
let sv: Validation.StringValidator = {
isAcceptable(s) {
return true;
},
};
let lov: Validation.LettersOnlyValidator =
new Validation.LettersOnlyValidator();
console.log({ sv, lov });
当文件内使用到了另一个文件内命名空间的内容时,需要在该文件内使用三斜线指令 来告诉编译器你引用的内容所在的位置,后继编译器就会根据三斜线指令的引用关系, 来决定整合文件的内容的顺序
编译后结果如下
// result.js
"use strict";
/// <reference path='nameC.ts' />
var Validation;
/// <reference path='nameC.ts' />
(function (Validation) {
const lettersRegexp = /^[A-Za-z]+$/;
class LettersOnlyValidator {
isAcceptable(s) {
return lettersRegexp.test(s);
}
}
Validation.LettersOnlyValidator = LettersOnlyValidator;
})(Validation || (Validation = {}));
/// <reference path='nameC.ts' />
/// <reference path='nameB.ts' />
let sv = {
isAcceptable(s) {
return true;
},
};
let lov = new Validation.LettersOnlyValidator();
console.log({ sv, lov });
运行result.js文件,发现能够正常运行并输出期望结果
原理
编译器在编译文件时有个步骤——预处理输入文件
,该步骤会对输入文件预处理来解析所有三斜线指令,在这个过程中额外的文件会被加入到编译过程中。
以上述代码为例,编译器在解析nameA.ts文件前,会先监测其文件内容有没有三斜线指令,结果发现有
/// <reference path='nameC.ts' />
/// <reference path='nameB.ts' />
那么编译器会先去对nameC.ts进行编译,发现nameC.ts中没有三斜线指令,则先将编译结果添加到输出文件中,后面继续解析nameB.ts 发现nameB.ts也使用三斜线指令指向了nameA.ts,不过其之前已经编译过,就不再处理,而是将nameB.ts内容编译后添加到输出文件中, 此时nameC.ts的三斜线指令已经预处理完毕,那么就将nameC.ts内容编译后添加到输出文件中,此时输出文件的内容便是我们预期的输出结果。
说大白话就是,/// <reference path='nameC.ts' />
就是告诉编译器:我这里使用了nameC.ts的内容,请你先去编译nameC.ts的内容后再来我这
如果有帮到您的话,请点个赞吧~ 谢谢!
转载自:https://juejin.cn/post/7368692841298804790