TypeScript 是 Microsoft 在 2012 年推出的程式語言。它的用途和 JavaScript 一樣,但是無法直接在瀏覽器上執行。而是要先藉由編譯器編譯成 JavaScript 檔之後,才能執行。TypeScript 有很多好用的語法,如物件導向 (Object-Oriented) 和範型 (Generic),加上要型別宣告。當開發大型專案時,TypeScript 就明顯地比 JavaScript 好用,如 Angular 就採用 TypeScript 作為第一語言。
Table of Contents
建立 TypeScript Node.js 專案
建立一個 Node.js 專案。
% mkdir TypeScriptExample % cd TypeScriptExample TypeScriptExample % npm init -y
安裝 TypeScript 模組。
TypeScriptExample % npm install --save-dev typescript
建立 TypeScript 的設定檔,它的預設檔名為 tsconfig.json。
TypeScriptExample % vi tsconfig.json
將以下的 JSON 放入 tsconfig.json。include 是指要 TypeScript 編譯器編譯的程式碼目錄。exclude 是指要 TypeScript 編譯器略過的目錄。
compilerOptions 是編譯器設定,它有很多的選項可以設定,這些可以在 Compiler Options 中查詢到。
- module:指定要輸出的 JavaScript 要用哪一種 Module 系統。 如 ES6 是用 import/export 語法。
- target:指定要輸出是什麼版本的 JavaScript。
- declaration:是否編譯器要產出 .d.ts 宣告檔。
- outDir:編譯後輸出的目的地。
- lib:編譯器要引入的 library 列表。例如,引入 DOM,編譯器才認得
window和document。 - allowJs:是否要允許編譯器可以編譯 JavaScript 檔。
- moduleResolution:指定編譯器要用什麼方式的 Module Resolution。
- strict:是否啟動所有的 type checking 選項。
- experimentalDecorators:是否啟用支援 ES Decorators。
{
"compilerOptions": {
"module": "esnext",
"target": "es6",
"declaration": true,
"outDir": "./lib",
"lib": [
"esnext",
"DOM"
],
"allowJs": false,
"moduleResolution": "node",
"strict": true,
"experimentalDecorators": true
},
"include": [
"./src"
],
"exclude": [
"node_modules"
]
}新增一個 TypeScrpt 檔叫 Person.ts。
TypeScriptExample % mkdir src TypeScriptExample % vi src/Person.ts
Person.ts 的內容簡單如下:
export class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
public toString(): string {
return this.name + ' is ' + this.age + ' years old.';
}
}將編譯器指令加入到 package.json 的 scripts 裡。
{
"name": "TypeScriptExample",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "tsc"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"typescript": "^3.9.6"
}
}然後執行指令編譯專案。
TypeScriptExample % npm run build
編譯後,編譯器將檔案輸出到 ./lib 下面。可以看到編譯後的 JavaScript 檔,和 .d.ts 宣告檔。
TypeScriptExample % ls lib Person.d.ts Person.js
TSLint
TSLint 是用來幫我們檢查 TypeScript 語法是否符合語法規範。在程式碼寫好後,讓 TSLint 來幫我們檢查程式碼是否有符合規範是很好的事情。讓我們將 TSLint 加入到專案吧!
安裝 TSLint。
TypeScriptExample % npm install --save-dev tslint
建立 TSLint 的語法規範設定檔,預設檔名是 tslint.json。
TypeScriptExample % vi tslint.json
TSLint 設定檔的設定選項有很多,可以在 Configuring TSLint 查詢。
把下面的內容放入我們的 tslint.json。它是延伸 tslint:recommended 這個預定義好的設定檔。然後我們加上每一行尾都要分號的設定。
{
"extends": "tslint:recommended",
"rules": {
"semicolon": {
"options": [
"always"
]
}
}
}修改 src/Person.ts,在第11行,把行尾的分號移除。等等 TSLint 應該要檢查到這個錯誤。
export class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
public toString(): string {
return this.name + ' is ' + this.age + ' years old.'
}
}將 TSLint 的指令將入到 package.json。-p 指定 tsconfig.json 給 TSLint,這樣它會知道程式碼在哪。
{
"name": "TypeScriptExample",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "tsc",
"lint": "tslint -p tsconfig.json"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"tslint": "^6.1.2",
"typescript": "^3.9.6"
}
}執行 TSLint 指令,可以看到它有檢查出有語法不符合規範。那就是我們剛剛移除行尾的分號。
TypeScriptExample % npm run lint > TypeScriptExample@1.0.0 lint /waynestalk/TypeScriptExample > tslint -p tsconfig.json /waynestalk/TypeScriptExample/src/Person.ts:11:57 ERROR: 11:57 semicolon Missing semicolon npm ERR! code ELIFECYCLE npm ERR! errno 2 npm ERR! TypeScriptExample@1.0.0 lint: `tslint -p tsconfig.json` npm ERR! Exit status 2 npm ERR! npm ERR! Failed at the TypeScriptExample@1.0.0 lint script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above. npm ERR! A complete log of this run can be found in: npm ERR! .npm/_logs/2020-07-08T04_51_16_291Z-debug.log
Webpack
Webpack 是一個 JavaScript 的 Bundle 工具。如果不了解 Webpack,這篇文章有詳細的教學。
藉由 ts-loader,我們可以讓 Webpack 處理 TypeScript。讓我們來看看要如何整合 Webpack。
安裝 webpack、webpack-cli 和 ts-loader 模組
TypeScriptExample % npm install --save-dev webpack webpack-cli ts-loader
新增 webpack.config.js,內容如下。如果不了解下面的內容,請先看完上面的 Webpack 教學。這個設定檔中,最主要的地方有兩個。一個就是 extensions 要設定為 ts 副檔名。另外一個就是加上 ts-loader,讓 Webpack 可以處以 TypeScript 檔。
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/Person.ts',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
publicPath: '/',
},
resolve: {
extensions: ['.ts', '.tsx'],
modules: ['node_modules'],
},
module: {
rules: [
{
test: /\.ts(x?)$/,
exclude: /node_modules/,
use: [
{
loader: 'ts-loader'
}
]
},
]
},
};最後在 package.json 中,把 npm run build 裡面的 tsc 改為 webpack。改用 Webpack 來編譯。
{
"name": "TypeScriptExample",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack",
"lint": "tslint -p tsconfig.json"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"ts-loader": "^7.0.5",
"tslint": "^6.1.2",
"typescript": "^3.9.6",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12",
"wepack-cli": "0.0.1-security"
}
}執行一下指令,看看結果有什麼不同。
TypeScriptExample % npm run build
> TypeScriptExample@1.0.0 build /TypeScriptExample
> webpack
Hash: 2fbb4aea58a915d46f3f
Version: webpack 4.43.0
Time: 726ms
Built at: 07/08/2020 10:07:19 PM
Asset Size Chunks Chunk Names
../lib/Person.d.ts 135 bytes [emitted]
main.bundle.js 1.07 KiB 0 [emitted] main
Entrypoint main = main.bundle.js
[0] ./src/Person.ts 194 bytes {0} [built]結語
如果你使用過 TypeScript 開發的話,你一定會對它愛不似手。雖然剛剛開始時,會因為型態宣告的繁瑣想要放棄,但是習慣了之後,你會發現型態宣告讓程式碼的可讀性大大地提升!





