TypeScript学习(二十二):TS 架构总览 | 八月更文挑战

616 阅读5分钟

这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战

架构分层

  • 核心:TS Compiler

  • Parser:string ---> AST

  • Binder:使用符号链接对统一结构有关联的声明,即,相同接口或模块的不同声明,或相同名称的模块和函数。这使得类型系统得以推理这些有命名的声明

  • 类型解析/检查:解析每个构造的类型,检查语义操作并且根据需要生成诊断信息

  • Emitter:通过输入文件(.ts 和 .d.ts)以生成一系列文件:js,.d.ts 或 sourcemap

  • Pre-processor:"编译上下文" 指的是所有在一个“program”中所涉及的所有文件。上下文通过检查在命令行传递给编译器的所有文件来创建。其创建顺序是通过直接或间接引用来决定,如,import 和 /// 。便利所有引用的结果是生成一个源文件的有序列表。当解析导入时,优先解析 ts 而非 .d.ts 文件以保证大部分最近文件被处理。编译器解析 import 行为与node相似,详见前面内容。失败的导入并不会导致错误,因为可能已经有一个 ambient 模块被声明了.

  • Standalone compiler (tsc):批处理编译CLI。主要支持不同引擎的文件读写。

  • Language Service:“Language Service”在核心编译流水线上暴露了额外的一层,这是最适合编辑器的应用。Language Service 支持一系列编辑器操作,比如,语句完成,函数签名,代码格式化及大纲,代码着色等。基本的重构比如重命名;debug 界面辅助,如验证断点及 TS 专属特性:增量编译( 通过 命令行 --watch 设置 )。Language service 旨在处理在长期编译上下文中文件变化情况;因此,与其他编译器不太一样,Language service 提供了关于处理程序与源文件的接口。详见

  • 单独的服务:tsserver 包含编译及服务层,通过 JSON 格式的通信再暴露给外界。LSP

数据结构

  • Node:AST 的基础节点。通常节点代表语言语法中的非终结符;一些终结符保存在 AST 树中,比如标志符和文字。

  • sourceFile:一个给定源文件的 AST。一个 sourceFile 自身就是一个节点。它提供了一系列的接口去获取源文件相关信息,如文本,引用,一系列标志符,文件中的位置与行号/字符号的映射关系。

  • Program:sourceFile的集合及一系列编译操作集合。program是类型系统与代码产物的入口。

  • Symbol:一个具名的声明。Symbol是绑定的结果。Symbols 连接在 AST 树中声明的节点与其他与节点有关系的实体。Symbol是语义系统的基本结构。

  • Type:Type 是语义系统的其他部分。 类型可以是具名的,比如类与接口;也可以是匿名的,比如对象类型。

  • Signature:语言中有三种类型的签名:调用签名,构造签名与索引签名。

编译过程总览

preprocess

处理引用关系,即,/// 与 import 来确定哪些文件是要被编译的。

parser

获取 AST 树。AST 树是以树的数据结构来表示用户编辑的文字。一个 SourceFile 对象表示一个给定文件的 AST 树,其中包含一些额外信息,如 文件名与文件内容。

binder

binder 遍历 AST 节点、产生(???)、绑定 Symbols。每个具名实体都会创建一个 Symbol。一些声明的节点可以命名相同的实体( 类型别名? )。这意味着一些不同的节点会有相同的 Symbol,并且每个 Symbol 可以追踪到其声明节点们,即,一对多的关系。例如,同名的一个类与一个命名空间可以合并并且有相同的Symbol。binder 掌控作用域并且确保每个 Symbol 在正确的域内被创建。

Program

createSoureceFile API 可以创建一个 SourceFile。

目前为止,Symbols 代表在一个单体文件中的命名实体(们)。但是一些生命可以合并多个文件,所以下一步是构建所有的文件,即 Program。

TypeChecker

从一个 Program 实例中可以创建一个 TypeChecker。TypeChecker是 TS 类型系统的核心。TypeChecker 负责指定不同文件的 Symbol,为 Symbol 分配类型,并且产生一些诊断信息,如错误信息。

TypeChecker 做的第一件事就是从不同的 SourceFile 中整合 Symbol,形成一个单体的 Symbol 表。

在初始化状态后,TypeChecker 准备去回答下列问题?

  • 对 Node 来说 Symbol 是什么?
  • 对 Symbol 来说 Type 是什么?
  • 在 AST 中哪些 Symbol 是可见的?
  • 对一个函数声明来说,哪些签名是可用的?
  • 对于一个文件来说,哪些错误是可以报告的?

TypeChecker 的所有计算都是惰性的。他只解析回答问题的必要信息;只会检查与手头问题有关的 Nodes/Symbols/Types ,不会尝试检验其他视图。

Emitter

Emitter 可以从一个给定的 Program 中被创建。Emitter 负责从给定的 SourceFile 中创建 .js/.jsx/.d.ts/.js.map 文件。

术语

Full Start/Token Start

ts.Node.getStart ---> 获取 node 开始的第一个token的位置

ts.Node.getFullStart ---> 从 node 拥有的第一个 token 位置

stackoverflow.com/a/24391813/…

Trivia

Trivia 代表对理解代码大体上不重要的比分如,空格,评论甚至是冲标记。

因为 trival 并不是标准语言的一部分,并且可以春现在任意 token 之间。并且并不包含在语法树中。但是,因为他们在实现重构与维持原始文本保真度的时候非常重要,因此仍然可以通过 TS 提供的 API 访问。

。。。不重要

最后

比 handbook 难翻译多了。。。。。。尽力了