本文首先介绍 TS 架构的各个组成,而后是涉及的数据结构,最后会介绍整个编译过程。git
原文: Architectural Overview
TS 架构层次如上图所示,下面将对每层进行分析。github
核心编译器位于最底层,它包含如下部分:typescript
.ts
和 .d.ts
文件转换成 .js
、.d.ts
和 .map
等文件。import
的文件,以及 /// <reference path=... />
指向的文件,归入到编译过程,从而构成了最终的编译上下文。经过遍历文件索引图,会获得一个已排序的源文件列表,这些文件列表就构成了整个应用程序。在解析 import
时,编译器会优先查找 .ts
和 .d.ts
文件,以确保处理的是最新的文件。编译器默认使用跟 Node.js 相似的模块定位方式,它会逐路径往上查找能匹配到指定模块名的 .ts
或 .d.ts
文件。若是没有定位到对应的模块,编译器也不必定抛出错误,由于该模块可能在环境模块中被声明了,好比 path
等 Node.js 内置模块。独立编译器在核心编译器的基础上额外提供了批量编译命令,它能针对不一样引擎(如 Node.js)采起不一样的文件读写策略。咱们经过 npm i typescript -g
后,得到的 tsc
命令实际就是这个独立编译器。它会处理咱们命令行中指定的文件,而后送入核心编译器进行编译。npm
语言服务为核心编译器封装了一层接口,尤为适用于编辑器一类的应用。
语言服务支持典型的编辑器操做,包括:服务器
--watch
)语言服务被设计用来专门处理这样的场景:在长时间存在的编译上下文中,源文件会随着时间不断的变化。
从这个角度来讲,相比于市面上的其余编译器接口,语言服务在对待程序和源码的处理方式上提供了较为不一样视角。数据结构
附: 详细的语言服务 API 使用文档
独立服务器 tsserver
对编译器和语言服务层进行了封装,对外暴露了一种基于 JSON 协议的接口,称为语言服务协议(LSP)。架构
附:详细的独立服务器 文档
VS Code 就是一个典型的使用语言服务的编辑器,它经过 LSP 来和语言服务通讯,从而实现良好的编码体验。编辑器
TS 编译器中使用到的主要数据结构有如下 6 类:函数
Node
: AST 的基本构建单元块。一般来讲,Node
表明了语法中的非终端节点。与非终端节点相对的终端节点,好比标识符、字面量等,也在 AST 中。SourceFile
:对应源文件的 AST 。SourceFile
自己是一个 Node
,它额外提供了一些接口,用于访问包括原始文本、文件包含的引用、标识符列表,以及字符位置映射。Program
:编译单元的全部 SourceFile
和编译选项的集合。它是类型系统和代码生成的主要入口。Symbol
:已命名的声明,由类型联合器所生成。它链接了 AST 中的声明节点和其余地方的同名声明实体。它是语义系统的基本构建单元块。Type
: 它是语义系统的另外一部分,它能够是具名的(如类、接口),也能够是匿名的(如对象字面量)。Signature
: TS 语言中包含三种类型签名:函数调用签名、构造函数签名和索引签名。整个编译过程从预处理开始。编码
1、 预处理器会找出全部 import
语句 和 reference
指令所依赖的文件,并把它们都列为待编译文件。
2、 解析器解析全部待编译文件,生成 AST Node
。这仅仅是以树的形式来抽象表示待编译文件。SourceFile
对象除了是表示文件的 AST 外,还有额外的信息,好比文件名、源码等。不过此时的 SourceFile
并无包含类型信息。
3、 类型联合器遍历 AST ,生成并绑定 Symbol
。每一个具名实体类型都会建立一个 Symbol
。要注意的是,不一样的多个声明节点可能有相同的类型名称。这就意味着不用的 Node
能够有相同的 Symbol
,每一个 Symbol
会跟踪全部跟它有关的 Node
。举例来讲,对于相同名称的 class
和 interface
,它们的类型会合并,而且指向相同的 Symbol
。类型联合器也会处理好做用域,以确保每一个 Symbol
处于正确的做用域范围内。
4、 生成 Symbol
以后,经过调用 createSourceFile
就能够生成具备 Symbol
的 SourceFile
了。不过,Symbol
表示的是单个文件中的具名实体类型,因为来自多个文件的同名类型声明能够合并,所以下一步须要经过 Program
对象来构建一个囊括全部文件的全局 Symbol
视图。
5、 Program
使用 createProgram
接口生成,它包括全部 SourceFile
以及 CompilerOptions
。
6、 针对 Program
建立一个 TypeChecker
,它是 TS 类型系统的核心。它主要负责理清来自多个文件的 Symbol
之间的关系,绑定 Type
到 Symbol
,以及生成语义诊断信息(好比错误信息)。具体来讲,TypeChecker
作的第一件事是把来自不一样 SourceFile
的 Symbol
整合到单个视图中,而后会建立一张 Symbol
表,用来记录全部的 Symbol
,来自不一样文件的同名 Symbol
会在这个记录过程当中完成合并。一旦 TypeChecker
完成初始化,它就能够处理关于当前 Program
的任何类型问题了,好比:
* 某个 `Node` 的 `Symbol` 是什么? * 某个 `Symbol` 的 `Type` 是什么? * AST 的某个局部有哪些 `Symbol` 是可见的? * 某个函数声明有哪些可用的 `Signature` ? * 某个文件应该报告哪些错误信息?
TypeChecker
的全部检查都是延迟计算的。若是问它一个问题,它只会检查与这个问题相关的必要信息。也就是说,它会只检查与当前问题相关的 Node
、Symbol
和 Type
,而不会尝试检查额外的信息。
7、 最后,针对 Program
也会建立一个代码生成器,它负责针对给定的 SourceFile
生成预期的代码文件,包括 .js
、.jsx
、.d.ts
和 .js.map
文件。