鍍金池/ 教程/ HTML/ 架構(gòu)概述
初始化項(xiàng)目結(jié)構(gòu)
聯(lián)合類型
介紹
介紹
介紹
編譯選項(xiàng)
TypeScript 1.6
介紹
介紹
發(fā)展路線圖
介紹
在MSBuild里使用編譯選項(xiàng)
可迭代性
TypeScript 1.3
介紹
介紹
TypeScript 1.1
變量聲明
即將到來(lái)的Angular 2框架是使用TypeScript開(kāi)發(fā)的。 因此Angular和TypeScript一起使用非常簡(jiǎn)單方便
tsconfig.json
介紹
介紹
介紹
在MSBuild里使用編譯選項(xiàng)
使用TypeScript的每日構(gòu)建版本
新建工程
枚舉
三斜線指令
結(jié)合ASP.NET v5使用TypeScript
TypeScript里的this
介紹
TypeScript 1.4
編碼規(guī)范
介紹
模塊解析
ASP.NET 4
架構(gòu)概述
介紹
介紹
ASP.NET Core
TypeScript 1.8
介紹
介紹
創(chuàng)建簡(jiǎn)單工程
TypeScript 1.7
TypeScript 1.5
NPM包的類型
支持TypeScript的編輯器

架構(gòu)概述

層次概述

Architectural overview.

  • 核心TypeScript編譯器

    • 語(yǔ)法分析器(Parser): 以一系列原文件開(kāi)始, 根據(jù)語(yǔ)言的語(yǔ)法, 生成抽象語(yǔ)法樹(shù)(AST)

    • 聯(lián)合器(Binder): 使用一個(gè)Symbol將針對(duì)相同結(jié)構(gòu)的聲明聯(lián)合在一起(例如:同一個(gè)接口或模塊的不同聲明,或擁有相同名字的函數(shù)和模塊)。這能幫助類型系統(tǒng)推導(dǎo)出這些具名的聲明。

    • 類型解析器與檢查器(Type resolver / Checker): 解析每種類型的構(gòu)造,檢查讀寫(xiě)語(yǔ)義并生成適當(dāng)?shù)脑\斷信息。

    • 生成器(Emitter): 從一系列輸入文件(.ts和.d.ts)生成輸出,它們可以是以下形式之一:JavaScript(.js),聲明(.d.ts),或者是source maps(.js.map)。

    • 預(yù)處理器(Pre-processor): “編譯上下文”指的是某個(gè)“程序”里涉及到的所有文件。上下文的創(chuàng)建是通過(guò)檢查所有從命令行上傳入編譯器的文件,按順序,然后再加入這些文件直接引用的其它文件或通過(guò)import語(yǔ)句和/// <reference path=... />標(biāo)簽間接引用的其它文件。

沿著引用圖走下來(lái)你會(huì)發(fā)現(xiàn)它是一個(gè)有序的源文件列表,它們組成了整個(gè)程序。

當(dāng)解析導(dǎo)出(import)的時(shí)候,會(huì)優(yōu)先選擇“.ts”文件而不是“.d.ts”文件,以確保處理的是最新的文件。 編譯器會(huì)進(jìn)行與Nodejs相似的流程來(lái)解析導(dǎo)入,沿著目錄鏈查找與將要導(dǎo)入相匹配的帶.ts或.d.ts擴(kuò)展名的文件。 導(dǎo)入失敗不會(huì)報(bào)error,因?yàn)榭赡芤呀?jīng)聲明了外部模塊。

  • 獨(dú)立編譯器(tsc): 批處理編譯命令行界面。主要處理針對(duì)不同支持的引擎讀寫(xiě)文件(比如:Node.js)。

  • 語(yǔ)言服務(wù): “語(yǔ)言服務(wù)”在核心編譯器管道上暴露了額外的一層,非常適合類編輯器的應(yīng)用。

語(yǔ)言服務(wù)支持一系列典型的編輯器操作比如語(yǔ)句自動(dòng)補(bǔ)全,函數(shù)簽名提示,代碼格式化和突出高亮,著色等。

基本的重構(gòu)功能比如重命名,調(diào)試接口輔助功能比如驗(yàn)證斷點(diǎn),還有TypeScript特有的功能比如支持增量編譯(在命令行上使用--watch)。 語(yǔ)言服務(wù)是被設(shè)計(jì)用來(lái)有效的處理在一個(gè)長(zhǎng)期存在的編譯上下文中文件隨著時(shí)間改變的情況;在這樣的情況下,語(yǔ)言服務(wù)提供了與其它編譯器接口不同的角度來(lái)處理程序和源文件。

請(qǐng)參考 [[Using the Language Service API]] 以了解更多詳細(xì)內(nèi)容。

數(shù)據(jù)結(jié)構(gòu)

  • Node: 抽象語(yǔ)法樹(shù)(AST)的基本組成塊。通常Node表示語(yǔ)言語(yǔ)法里的非終結(jié)符;一些終結(jié)符保存在語(yǔ)法樹(shù)里比如標(biāo)識(shí)符和字面量。

  • SourceFile: 給定源文件的AST。SourceFile本身是一個(gè)Node;它提供了額外的接口用來(lái)訪問(wèn)文件的源碼,文件里的引用,文件里的標(biāo)識(shí)符列表和文件里的某個(gè)位置與它對(duì)應(yīng)的行號(hào)與列號(hào)的映射。

  • Program: SourceFile的集合和一系列編譯選項(xiàng)代表一個(gè)編譯單元。Program是類型系統(tǒng)和生成代碼的主入口。

  • Symbol: 具名的聲明。Symbols是做為聯(lián)合的結(jié)果而創(chuàng)建。Symbols連接了樹(shù)里的聲明節(jié)點(diǎn)和其它對(duì)同一個(gè)實(shí)體的聲明。Symbols是語(yǔ)義系統(tǒng)的基本構(gòu)建塊。

  • Type: Type是語(yǔ)義系統(tǒng)的其它部分。Type可能被命名(比如,類和接口),或匿名(比如,對(duì)象類型)。

  • Signature: 一共有三種Signature類型:調(diào)用簽名(call),構(gòu)造簽名(construct)和索引簽名(index)。

編譯過(guò)程概述

整個(gè)過(guò)程從預(yù)處理開(kāi)始。 預(yù)處理器會(huì)算出哪些文件參與編譯,它會(huì)去查找如下引用(/// <reference path=... />標(biāo)簽和import語(yǔ)句)。

語(yǔ)法分析器(Parser)生成抽象語(yǔ)法樹(shù)(AST)Node. 這些僅為用戶輸出的抽象表現(xiàn),以樹(shù)的形式。 一個(gè)SourceFile對(duì)象表示一個(gè)給定文件的AST并且?guī)в幸恍╊~外的信息如文件名及源文件內(nèi)容。

然后,聯(lián)合器(Binder)處理AST節(jié)點(diǎn),結(jié)合并生成Symbols。 一個(gè)Symbol會(huì)對(duì)應(yīng)到一個(gè)命名實(shí)體。 這里有個(gè)一微妙的差別,幾個(gè)聲明節(jié)點(diǎn)可能會(huì)是名字相同的實(shí)體。 也就是說(shuō),有時(shí)候不同的Node具有相同的Symbol,并且每個(gè)Symbol保持跟蹤它的聲明節(jié)點(diǎn)。 比如,一個(gè)名字相同的classnamespace可以合并,并且擁有相同的Symbol。 聯(lián)合器也會(huì)處理作用域,以確保每個(gè)Symbol都在正確的封閉作用域里創(chuàng)建。

生成SourceFile(還帶有它的Symbols們)是通過(guò)調(diào)用createSourceFile API。

到目前為止,Symbol代表的命名實(shí)體可以在單個(gè)文件里看到,但是有些聲明可以從多文件合并,因此下一步就是構(gòu)建一個(gè)全局的包含所有文件的視圖,也就是創(chuàng)建一個(gè)Program

一個(gè)ProgramSourceFile的集合并帶有一系列CompilerOptions。 通過(guò)調(diào)用createProgram API來(lái)創(chuàng)建Program。

通過(guò)一個(gè)Program實(shí)例創(chuàng)建TypeCheckerTypeChecker是TypeScript類型系統(tǒng)的核心。 它負(fù)責(zé)計(jì)算出不同文件里的Symbols之間的關(guān)系,將Type賦值給Symbol,并生成任何語(yǔ)義Diagnostic(比如:error)。

TypeChecker首先要做的是合并不同的SourceFile里的Symbol到一個(gè)單獨(dú)的視圖,創(chuàng)建單一的Symbol表,合并所有普通的Symbol(比如:不同文件里的namespace)。

在原始狀態(tài)初始化完成后,TypeChecker就可以解決關(guān)于這個(gè)程序的任何問(wèn)題了。 這些“問(wèn)題”可以是:

  • 這個(gè)NodeSymbol是什么?
  • 這個(gè)SymbolType是什么?
  • 在AST的某個(gè)部分里有哪些Symbol是可見(jiàn)的?
  • 某個(gè)函數(shù)聲明的Signature都有哪些?
  • 針對(duì)某個(gè)文件應(yīng)該報(bào)哪些錯(cuò)誤?

TypeChecker計(jì)算所有東西都是“懶惰的”;為了回答一個(gè)問(wèn)題它僅“解決”必要的信息。 TypeChecker僅會(huì)檢測(cè)和這個(gè)問(wèn)題有關(guān)的NodeSymbolType,不會(huì)檢測(cè)額外的實(shí)體。

對(duì)于一個(gè)Program同樣會(huì)生成一個(gè)EmitterEmitter負(fù)責(zé)生成給定SourceFile的輸出;它包括:.js,.jsx,.d.ts.js.map

術(shù)語(yǔ)

完整開(kāi)始/令牌開(kāi)始(Full Start/Token Start)

令牌本身就具有我們稱為一個(gè)“完整開(kāi)始”和一個(gè)“令牌開(kāi)始”。“令牌開(kāi)始”是指更自然的版本,它表示在文件中令牌開(kāi)始的位置?!巴暾_(kāi)始”是指從上一個(gè)有意義的令牌之后掃描器開(kāi)始掃描的起始位置。當(dāng)關(guān)心瑣事時(shí),我們往往更關(guān)心完整開(kāi)始。

函數(shù) 描述
ts.Node.getStart 取得某節(jié)點(diǎn)的第一個(gè)令牌起始位置。
ts.Node.getFullStart 取得某節(jié)點(diǎn)擁有的第一個(gè)令牌的完整開(kāi)始。

瑣碎內(nèi)容(Trivia)

語(yǔ)法的瑣碎內(nèi)容代表源碼里那些對(duì)理解代碼無(wú)關(guān)緊要的內(nèi)容,比如空白,注釋甚至一些沖突的標(biāo)記。

因?yàn)楝嵥閮?nèi)容不是語(yǔ)言正常語(yǔ)法的一部分(不包括ECMAScript API規(guī)范)并且可能在任意2個(gè)令牌中的任意位置出現(xiàn),它們不會(huì)包含在語(yǔ)法樹(shù)里。但是,因?yàn)樗鼈儗?duì)于像重構(gòu)和維護(hù)高保真源碼很重要,所以需要的時(shí)候還是能夠通過(guò)我們的APIs訪問(wèn)。

因?yàn)?code>EndOfFileToken后面可以沒(méi)有任何內(nèi)容(令牌和瑣碎內(nèi)容),所有瑣碎內(nèi)容自然地在非瑣碎內(nèi)容之前,而且存在于那個(gè)令牌的“完整開(kāi)始”和“令牌開(kāi)始”之間。

雖然這個(gè)一個(gè)方便的標(biāo)記法來(lái)說(shuō)明一個(gè)注釋“屬于”一個(gè)Node。比如,在下面的例子里,可以明顯看出genie函數(shù)擁有兩個(gè)注釋:

var x = 10; // This is x.

/**
 * Postcondition: Grants all three wishes.
 */
function genie([wish1, wish2, wish3]: [Wish, Wish, Wish]) {
    while (true) {
    }
} // End function

這是盡管事實(shí)上,函數(shù)聲明的完整開(kāi)始是在var x = 10;后。

我們依據(jù)處理注釋所有權(quán)。通常來(lái)講,一個(gè)令牌擁有同一行上的所有的瑣碎內(nèi)容直到下一個(gè)令牌開(kāi)始。任何出現(xiàn)在這行之后的注釋都屬于下一個(gè)令牌。源文件的第一個(gè)令牌擁有所有的初始瑣碎內(nèi)容,并且最后面的一系列瑣碎內(nèi)容會(huì)添加到end-of-file令牌上。

對(duì)于大多數(shù)普通用戶,注釋是“有趣的”瑣碎內(nèi)容。屬于一個(gè)節(jié)點(diǎn)的注釋內(nèi)容可以通過(guò)下面的函數(shù)來(lái)獲?。?/p>

函數(shù) 描述
ts.getLeadingCommentRanges 提供源文件和一個(gè)指定位置,返回指定位置后的第一個(gè)換行與令牌之間的注釋的范圍(與ts.Node.getFullStart配合會(huì)更有用)。
ts.getTrailingCommentRanges 提供源文件和一個(gè)指定位置,返回到指定位置后第一個(gè)換行為止的注釋的范圍(與ts.Node.getEnd配合會(huì)更有用)。

做為例子,假設(shè)有下面一部分源代碼:

debugger;/*hello*/
    //bye
  /*hi*/    function

function關(guān)鍵字的完整開(kāi)始是從/*hello*/注釋,但是getLeadingCommentRanges僅會(huì)返回后面2個(gè)注釋:

d e b u g g e r ; / * h e l l o * / _ _ _ _ _ [CR] [NL] _ _ _ _ / / b y e [CR] [NL] _ _ / * h i * / _ _ _ _ f u n c t i o n
                  ↑                                     ↑       ↑                       ↑                   ↑
                  完整開(kāi)始                              查找      第一個(gè)注釋               第二個(gè)注釋     令牌開(kāi)始
                                                       開(kāi)始注釋

適當(dāng)?shù)兀?code>debugger語(yǔ)句后調(diào)用getTrailingCommentRanges可以提取出/*hello*/注釋。

如果你關(guān)心令牌流的更多信息,createScanner也有一個(gè)skipTrivia標(biāo)記,你可以設(shè)置成false,然后使用setText/setTextPos來(lái)掃描文件里的不同位置。