TypeScript -組態檔與宣告檔

by vivid 3. 四月 2019 03:56

.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號: N190420601
出刊日期: 2019/4/3

在這篇文章中,將要介紹TypeScript組態設定檔案的基本用法,以及常用的選項設定以進一步控制程式編譯的細節,並了解如何透過宣告檔案來描述型別資訊。

 

「tsconfig.json」組態設定檔案

「tsconfig.json」檔案用來指定TypeScript程式編譯的選項,以便於引導編譯器編譯程式碼。「tsconfig.json」檔案所在的資料夾就是TypeScript專案的根目錄。

只要利用命令提示字元,專案根目錄輸入以下指令,就可以為專案建立一個「tsconfig.json」檔案:

tsc --init

這個檔案預設將包含以下內容:

{
  "compilerOptions": {
    /* Basic Options */
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    // "lib": [],                             /* Specify library files to be included in the compilation. */
    // "allowJs": true,                       /* Allow javascript files to be compiled. */
    // "checkJs": true,                       /* Report errors in .js files. */
    // "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    // "declaration": true,                   /* Generates corresponding '.d.ts' file. */
    // "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */
    // "sourceMap": true,                     /* Generates corresponding '.map' file. */
    // "outFile": "./",                       /* Concatenate and emit output to single file. */
    // "outDir": "./",                        /* Redirect output structure to the directory. */
    // "rootDir": "./",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
    // "composite": true,                     /* Enable project compilation */
    // "removeComments": true,                /* Do not emit comments to output. */
    // "noEmit": true,                        /* Do not emit outputs. */
    // "importHelpers": true,                 /* Import emit helpers from 'tslib'. */
    // "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
    // "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

    /* Strict Type-Checking Options */
    "strict": true,                           /* Enable all strict type-checking options. */
    // "noImplicitAny": true,                 /* Raise error on expressions and declarations with an implied 'any' type. */
    // "strictNullChecks": true,              /* Enable strict null checks. */
    // "strictFunctionTypes": true,           /* Enable strict checking of function types. */
    // "strictBindCallApply": true,           /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
    // "strictPropertyInitialization": true,  /* Enable strict checking of property initialization in classes. */
    // "noImplicitThis": true,                /* Raise error on 'this' expressions with an implied 'any' type. */
    // "alwaysStrict": true,                  /* Parse in strict mode and emit "use strict" for each source file. */

    /* Additional Checks */
    // "noUnusedLocals": true,                /* Report errors on unused locals. */
    // "noUnusedParameters": true,            /* Report errors on unused parameters. */
    // "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
    // "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */

    /* Module Resolution Options */
    // "moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    // "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
    // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
    // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
    // "typeRoots": [],                       /* List of folders to include type definitions from. */
    // "types": [],                           /* Type declaration files to be included in compilation. */
    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    // "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */

    /* Source Map Options */
    // "sourceRoot": "",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. */
    // "mapRoot": "",                         /* Specify the location where debugger should locate map files instead of generated locations. */
    // "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */
    // "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */

    /* Experimental Options */
    // "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
    // "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
  }
}


預設這個檔案中可以完全不包含任何編譯選項設定,但檔案內容不可以是空白,至少需要有一個空物件,參考以下範例程式碼:

{}

若檔案內容空白,則會發生編譯錯誤,錯誤訊息為:

error TS6053: File 'C:/temp/TS/tsconfig.json' not found.

有了「tsconfig.json」組態設定檔案後,編譯器將會根據預設值來進行編譯。此外若在命令列使用編譯器選項,那麼這些選項設定將會優先蓋過「tsconfig.json」檔案中的編譯選項設定。

當你使用「tsc.exe」檔案編譯程式,且沒有指定來源檔案時,編譯器會先搜尋目前的資料夾、父資料夾中是否有「tsconfig.json「檔案,以決定要編譯哪些程式碼。若在命令列編譯指定的檔案時,這個檔案的設定就會被忽略。

我們來看一個簡單的「tsconfig.json」檔案組態範例,參考如下程式碼:

{
  "compilerOptions": {
    "target": "es2015"
  },
  "files": [
    "./02_start.ts",
    "./01_start.ts"
  ]
}

「compilerOptions」屬性,預設可省略直接使用預設值便可,它是用來告知編譯器編譯的選項,其中的「target」屬性表示要將程式編譯成指定的ECMAScript版本,預設值為「ES3」,你可以將其設定為「ES5」、「ES6」、「ES2015」、「ES2016」、「ES2017」或「ESNext」等等。

「files」屬性用來設定要編譯的TypeScript程式檔案,你可以使用絕對檔案路徑或相對檔案路徑的語法來描述。例如範例中要求編譯「01_start.ts」與「02_start.ts」兩個檔案。另外一種指定檔案的方式是採用「include」與「exclude」屬性,參考以下範例程式碼:

{
  "compilerOptions": {
    "target": "es2015"
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "temp/**/*"
  ]
}

「include」與「exclude」屬性使用glob-like 檔案模式(file patterns),最常見的萬用字元為「*」號,表示找尋0到多個字元。「?」號則找尋一個相符字元;「[...]」則找尋在一個範圍中的字元。「**/」表示搜尋所有資料夾以及子資料夾。

若「tsconfig.json」檔案中沒有指定「include」與「files」屬性,則預設會編譯目前資料夾以及所有子資料夾中所有的TypeScript檔案,包含附檔名為「.ts」、「.tsx」檔案。若同時指定「include」與「files」兩個屬性,則與兩個屬性設定相符的檔案或資料夾中的檔案都會被編譯。

繼承組態檔案

「tsconfig.json」檔案中的設定可以利用「extends」屬性來繼承其它檔案的組態設定。例如以下範例程式碼,假設在專案根目錄下有一個「baseConfig.json」檔案,包含以下組態設定,指明要編譯「src」資料夾中的程式檔案為「ES2015」語法:

{
  "compilerOptions": {
    "target": "es2015"
  },
  "include": [
    "src/**/*"
  ]
}

 

而在專案根目錄下有一個「tsconfig.json」檔案,設定組態如下,利用「extends」屬性繼承「baseConfig.json」檔案的設定:

{

"extends": "./baseConfig"

}

若使用命令列在專案根目錄下執行「tsc」將編譯「src」資料夾下的程式檔案,而「tsconfig.json」檔案包含了「files」、「include」、「exclude」屬性,則「tsconfig.json」檔案中的設定將會覆蓋掉「baseConfig.json」檔案的設定,舉例來說,若「tsconfig.json」檔案的內容如下:

 

{
  "extends": "./baseConfig",
  "include": [
    "module/**/*"
  ]
}

 

那麼,編譯器將編譯「module」資料夾中的程式碼檔案,而不編譯「src」資料夾中的程式碼檔案。

常用的「compilerOptions」選項

常用的「compilerOptions」選項包含如下:

  • 「allowJs」屬性:是否允許編譯JavaScript。預設值為「false」。
  • 「alwaysStrict」屬性:以嚴格模式解析程式碼,並在每個檔案最上方加上「"use strict";」這行程式碼。
  • 「charset」屬性:輸入檔案的字元集。
  • 「checkJs」屬性:預設為「false」,搭配「allowJs」屬性一起使用,是否回報js檔案中的錯誤。
  • 「declaration」屬性:預設為「false」,若設為「true」則表示要產生對應的「*.d.ts」檔案。
  • 「declarationDir」屬性:用來指明產生的「*.d.ts」檔案要存放的資料夾。
  • 「declarationMap」屬性:預設為「false」,若設為「true」則表示要產生「*.d.ts」檔案對應的sourcemap檔案。
  • 「emitDeclarationOnly」屬性:預設為「false」,若設為「true」則表示只要產生「*.d.ts」檔案。
  • 「jsx」屬性:是否支援「*.tsx」檔案。
  • 「lib」屬性:編譯階段包含的程式庫檔案清單。
  • 「outDir」屬性:指定要產生程式碼存放所在的資料夾。
  • 「outFile」屬性:指定要輸出的程式碼檔案名稱。
  • 「target」屬性:表示要將程式編譯成指定的ECMAScript版本,預設值為「ES3」,你可以將其設定為「ES5」、「ES6」、「ES2015」、「ES2016」、「ES2017」或「ESNext」。
  • 「typeRoots」屬性:為字串陣列,描述宣告檔案所在的可能資料夾。預設宣告檔案存放於「node_modules/@types」資料夾。
  • 「types」屬性:明確指定要包含的宣告檔案之型別。

宣告檔案(Declaration File)

接下來我們來談談宣告檔案(Declaration File)的用途,以及為何要有宣告檔案。若我們的TypeScript程式碼有一個自訂的「Employee」物件,只具有「empId」、「empName」與「age」屬性,因為程式碼中未提供型別資訊,那麼若我們誤叫用了「Employee」物件的「getInfo()」方法,在TypeScript中將程式轉譯成JavaScript時,在轉譯與編譯程式碼的接斷都不會發生錯誤。舉例來說,若有一個「app.ts」檔案內容如下:

let emp ;
emp = {
   empId: 1,
   empName: "Mary",
   age: 25
};

let info = emp.getInfo();
console.log( info );


使用「tsc」工具將其轉換成JavaScript程式碼:

tsc app.ts

轉換的動作成功完成後,得到以下程式碼,和原始程式碼的內容相同。

let emp ;
emp = {
   empId: 1,
   empName: "Mary",
   age: 25
};

let info = emp.getInfo();
console.log( info );

 

不過當我們使用「ts-node」執行TypeScript時:

ts-node "c:\temp\TS\src\app.ts"

在執行階段便會發生錯誤,因為叫用到不存在於「emp」物件的「getInfo」方法,發生的訊息為「TypeError: emp.getInfo is not a function」,請參考下圖所示:

clip_image002

圖 1:執行階段發生錯誤。

TypeScript使用宣告檔案(Declaration File,附檔名為「.d.ts」)來了解模組中的型別,例如模組中有哪些介面(Interface)、類別(class)、型別與函式簽名。有了這個檔案之後,開發工具便可以更容易為程式提供程式提示,以及型別檢查功能。

因此,若想要在編譯階段讓TypeScript幫我們檢查「emp」物件是否包含有「getInfo」方法,不要等到執行階段才發生例外錯誤,你可以利用宣告檔案(Declaration File)來處理這個問題,它可以用來描述物件包含哪些屬性或方法。

我們可以為「Employee」物件定義型別宣告檔案,舉例來說在「app.d.ts」檔案包含以下程式碼,定義一個「CustomTypes」模組,並匯出一個「Employee」介面,描述「Employee」物件具備「empId」、「empName」、「age」三個屬性:

 

declare module CustomTypes {
  export interface Employee {
    empId: number;
    empName: string;
    age: number;
  }
}

 

接著修改「app.ts」檔案的程式碼如下,在檔案上方使用三個斜線與「reference」標籤描述宣告檔案所在位置,同時宣告「emp」變數時,明確指定其型別為「CustomTypes.Employee」:

/// <reference path="app.d.ts" />
let emp: CustomTypes.Employee;
emp = {
   empId: 1,
   empName: "Mary",
   age: 25
};

let info = emp.getInfo();
console.log( info );


那麼不需要等到執行階段,在程式開發階段,開發工具,例如Visual Studio Code就會根據宣告檔案自動進行型別檢查,並提示錯誤,請參考下圖所示:

clip_image004

圖 2:開發工具將可進行型別檢查,並提示錯誤。

搜尋宣告檔案

宣告檔案用來為JavaScript提供型別資訊。TypeScript在2.0版之後,預設會自動搜尋以下資料夾,以及其下的子資料夾,來找尋宣告檔案(副檔名為「.d.ts」):

/專案根資料夾/node_modules/@types

你可以利用TypeSearch網站來找尋並安裝常用的JavaScript程式庫的型別宣告檔案:

http://microsoft.github.io/TypeSearch/

請參考下圖所示:

clip_image006

圖 3:找尋常用的JavaScript程式庫的型別宣告檔案。

然後利用「npm」進行安裝宣告檔案。例如想要使用「lodash」,可以在命令提示字元專案根資料夾下執行以下「npm」命令:

npm install --save @types/lodash

宣告檔案將被安裝到「node_modules\@types\ lodash」資料夾之中。

因此,我們可以將宣告檔案放此資料夾下,例如在「node_modules\@types\customtypes」資料夾中建立一個「index.d.ts」檔案,然後將型別宣告的程式碼放在此檔案中:(注意,宣告檔案的名稱預設要命為「index.d.ts」),請參考下圖所示:

clip_image008

圖 4:定義宣告檔案。

那麼便可改寫「app.ts」檔案中的程式碼如下,不需要使用三個斜線與「reference」標籤描述宣告檔案所在位置:

let emp: CustomTypes.Employee;
emp = {
   empId: 1,
   empName: "Mary",
   age: 25
};

let info = emp.getInfo();
console.log( info );

 

如此TypeScript將會自動搜尋「\專案根目錄\node_modules\@types\customtypes」資料夾找到「index.d.ts」宣告檔案來進行型別檢查,請參考下圖所示:

clip_image010

圖 5:進行型別檢查。

若宣告檔案不在「/專案根目錄/node_modules/@types/customtypes」資料夾或其子資料夾下,那麼你可以利用「tsconfig.json」檔案指定檔案所在的資料夾,並將宣告檔案命名為「index.d.ts」。有「index.d.ts」檔案的這個資料夾稱做「types package」。

若「index.d.ts」檔案存在於「/專案根目錄/src/customtypes」資料夾,你可以設定「typeRoots」屬性為["./node_modules/@types", "./src"],陣列中第一個項目是預設的「/專案根目錄/node_modules/@types」資料夾;第二個項目是自訂的「/專案根目錄/src」資料夾,TypeScript編譯器會自動找尋「/專案根目錄/src/customtypes」資料夾中的「index.d.ts」檔案來讀取型別資訊:

 

{
  "compilerOptions": {
    "target": "es2015",
    "outDir": "js",
    "typeRoots": [
      "./node_modules/@types",
      "./src"
      ]
  },
  "include": [
    "src/**/*"
  ]
}

Tags:

.NET Magazine國際中文電子雜誌 | TypeScript | 許薰尹Vivid Hsu

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List