共计 2884 个字符,预计需要花费 8 分钟才能阅读完成。
- 三斜线指令用主要用于声明文件 & 文件 (
///
)、文件 & 第三方模块(///
) 之间的依赖关系 - 三斜线指令 最好只 出现在你手动编写声明文件 (即.d.ts 文件) 的场景
///
还有用于控制输出文件内容顺序的作用- 三斜线指令的引用路径是相对于包含它的文件的
- 三斜线指令出现在非声明文件的情况
前置知识
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 文件,发现报错:
`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 的内容后再来我这
如果有帮到您的话,请点个赞吧~ 谢谢!