TypeScript 提供了編譯 (compiler) 的 API 出來,可以讓我們用程式的方式建立或是編輯 ts 檔案。但為什麼要了解 TypeScript 的 Compiler API 呢? 主要原因是當在寫 Angular Schematics 時,加減都會碰到編輯 TypeScript 檔案的時候,這時候透過 TS Compiler API 來操作會比較保險一點,但這主題有點大,這一篇文章就稍微了解一下如何入門就好
環境準備
環境的準備很簡單,基本上安裝 TypeScript 1.6 版本以上的都可以,目前的版本是 3.0
1 | npm install -g typescript |
起手式
1 | import * as ts from 'typescript'; |
執行結果
第一個 console.log 結果
第二個 console.log 結果
程式碼說明
-
line 1:從 typescript 載入所有並指定別名
-
line 2:建立 Printer,用來列印內容用
-
line 3:
createSourceFile
建立SourceFile
1
function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes?: boolean, scriptKind?: ScriptKind): SourceFile;
sourceFile
的檔名sourceText
檔案內容languageVersion
TypeScript 版本
Node factories
TypeScript Compiler API 內件很多建立的方法,
以下舉出幾個 method 的用法集效果
-
createAdd
:將兩個ts.Expression
用+
串接在一起1
2const add = ts.createAdd(ts.createLiteral(42), ts.createLiteral(50));
const result = printer.printNode(ts.EmitHint.Unspecified, add, sourceFile); -
createArrayLiteral
:建立 array1
2
3
4const display = ts.createArrayLiteral(
/* elements?: ReadonlyArray<Expression> */ [ts.createLiteral('a'), ts.createLiteral('b')],
/* multiLine?: boolean */ true
); -
createArrowFunction
: 建立 arrow function1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17const arrowFunction = ts.createArrowFunction(
/* modifiers */ [],
/* typeParameters */ [],
/* parameters */ [
ts.createParameter(
[],
[],
undefined,
'x',
undefined,
ts.createTypeReferenceNode('number', [])
)
],
/* type */ ts.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
/* equalsGreaterThanToken */ undefined,
/* body */ ts.createLiteral(42)
); -
createArrayTypeNode
:建立某型別陣列型別1
2
3ts.createArrayTypeNode(
ts.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
); -
createAsExpression
:建立as 型別
的程式碼1
2
3
4
5
6const display = ts.createAsExpression(
ts.createObjectLiteral([
ts.createPropertyAssignment('name', ts.createLiteral('Kevin'))
]),
ts.createTypeReferenceNode('Person', undefined)
); -
createAssignment
: 建立指定程式碼1
2
3
4ts.createAssignment(
ts.createIdentifier('firstName'),
ts.createLiteral('Kevin')
); -
createVariableDeclarationList
:建立變數1
2
3
4ts.createVariableDeclarationList(
[ts.createVariableDeclaration('name', undefined, ts.createLiteral('yooo'))],
ts.NodeFlags.Const
);
在 TypeScript Compiler 裡面有超級多方法可以用來建立 typescript 的程式碼,但因為在網路上並沒有看到完整的 API 文件,這個就要慢慢花時間一個一個得看了
AST
AST 是 Abstract Syntax Tree 的縮寫,基本上就是將 TypeScript 檔案的內容轉換成樹狀結構的資料格式,可以透過分析 AST 的結構,進而做一些有趣的變化,但這邊就先針對結構做些了解,結構如下圖
sourceFile
(例如透過 ts.createSourceFile
建立) 內的所有訊息都會被轉換成 node 資訊 (同時也是一份 sourceFile
),每一個 node 資訊都會包含一個 kind
的類別,而這個類別與 ts.SyntaxKind
是對應上的,當然 TypeScript 內也有一些內建的方法來判斷目前的 node 是屬於哪種性質的,例如,使用 ts.isVariableDeclarationList
就可以判斷這一個 node 是否為宣告變數的程式,或是透過 node.kind === ts.SyntaxKind.xxxx
來判斷
TypeScript 編譯的步驟(如上圖)大致上是這樣子,我們可以在中間加上轉換外掛的功能,然後將輸出的結果變成我們想要的,可以在 tsconfig
內做設定
1 | import * as ts from 'typescript'; |
這裡提供一個簡單的程式碼做個開始,在搭配上一小結的建立方法,就可以改變最終的輸出結果了