第 1 課:TypeScript 是什麼?
學習目標
- 理解 TypeScript 嘅基本概念以及佢同 JavaScript 之間嘅關係
- 明白點解要學習 TypeScript,以及佢嘅主要優勢
- 體驗 TypeScript 嘅基本類型註解
- 學會使用互動編輯器進行簡單練習
1. TypeScript 簡介
TypeScript 其實係 JavaScript 嘅一個「超集」(superset)。意思即係,任何有效嘅 JavaScript 程式碼都係有效嘅 TypeScript 程式碼,但 TypeScript 喺 JavaScript 嘅基礎上,加入咗一啲額外嘅功能,最重要嘅就係「靜態類型系統」(static type system)。
TypeScript 嘅歷史同背景
TypeScript 係由 Microsoft 喺 2012 年開發嘅開源程式語言。當時 JavaScript 雖然功能強大,但缺乏類型檢查,令大型專案變得難以維護。TypeScript 嘅出現就係為咗解決呢個問題。
發展歷程:
- 2012年:Microsoft 發布 TypeScript 0.8
- 2014年:TypeScript 1.0 正式發布
- 2016年:Angular 2 採用 TypeScript 作為主要開發語言
- 2020年:TypeScript 4.0 發布,功能更加完善
- 現在:被廣泛應用於各種大型專案
靜態類型 vs 動態類型
動態類型(JavaScript):
- 變數嘅類型喺執行時才確定
- 靈活但容易出錯
- 錯誤通常喺執行時先發現
靜態類型(TypeScript):
- 變數嘅類型喺編寫時就確定
- 較嚴格但更安全
- 錯誤喺編寫時就可以發現
JavaScript vs TypeScript 對比
1// JavaScript - 動態類型,執行時才知道問題
2let message = "Hello, JavaScript!";
3message = 100; // 完全冇問題,但可能引致後續問題
4console.log(message.toUpperCase()); // 執行時先會爆錯!
5
6// TypeScript - 靜態類型,寫程式碼時就發現問題
7let messageTS: string = "Hello, TypeScript!";
8// messageTS = 100; // TypeScript 編譯器會即刻報錯
9console.log(messageTS.toUpperCase()); // 安全!TypeScript 嘅編譯過程
TypeScript 唔係直接執行嘅,而係需要「編譯」(compile)成 JavaScript:
1TypeScript 程式碼 (.ts) → TypeScript 編譯器 (tsc) → JavaScript 程式碼 (.js)呢個過程中,TypeScript 編譯器會:
- 檢查類型錯誤:確保所有變數同函式嘅類型都正確
- 移除類型註解:因為 JavaScript 唔理解類型註解
- 轉換新語法:將較新嘅 JavaScript 語法轉換為較舊版本
- 生成 JavaScript:輸出可以喺瀏覽器或 Node.js 執行嘅程式碼
🎯 互動練習 1:執行你嘅第一個 TypeScript 程式
2. 點解要學 TypeScript?
主要優勢
🔍 及早發現錯誤 TypeScript 可以喺你寫程式碼嘅時候就發現好多錯誤,而唔係等到程式執行時
📖 程式碼更清晰 類型註解令其他人(包括未來嘅你)更容易理解程式碼
🔧 更好嘅開發體驗 編輯器可以提供更準確嘅自動完成和提示
🏗️ 適合團隊合作 清晰嘅類型定義減少團隊成員之間嘅誤解
詳細優勢分析
1. 類型安全(Type Safety)
喺 JavaScript 中,以下程式碼係完全合法嘅,但會導致執行時錯誤:
1// JavaScript - 潛在問題
2function calculateArea(width, height) {
3 return width * height;
4}
5
6// 呢啲調用都唔會報錯,但結果可能唔係你想要嘅
7calculateArea("10", "20"); // 結果係 "1020" (字串連接)
8calculateArea(10); // 結果係 NaN (height 係 undefined)
9calculateArea(10, 20, 30); // 忽略第三個參數喺 TypeScript 中,呢啲問題會喺編寫時就被發現:
1// TypeScript - 類型安全
2function calculateArea(width: number, height: number): number {
3 return width * height;
4}
5
6// 呢啲調用會立即報錯
7// calculateArea("10", "20"); // 錯誤:參數類型不匹配
8// calculateArea(10); // 錯誤:缺少參數
9// calculateArea(10, 20, 30); // 錯誤:參數過多2. 更好嘅 IDE 支援
TypeScript 提供咗豐富嘅開發工具支援:
- 智能提示:編輯器知道變數嘅類型,可以提供準確嘅方法建議
- 自動重構:安全地重命名變數、函式等
- 跳轉定義:快速跳轉到函式或變數嘅定義位置
- 錯誤提示:即時顯示類型錯誤
3. 大型專案嘅可維護性
隨著專案規模增大,TypeScript 嘅優勢更加明顯:
- 介面定義:清楚定義物件嘅結構
- 模組系統:更好嘅程式碼組織
- 重構安全:修改程式碼時減少破壞其他部分嘅風險
實際應用場景
企業級應用
- Microsoft Office Online:Microsoft 自己嘅產品大量使用 TypeScript
- Slack:團隊協作工具,處理複雜嘅即時通訊邏輯
- Airbnb:房屋租賃平台,管理大量用戶數據
開源專案
- Angular:Google 開發嘅前端框架
- Vue 3:流行嘅前端框架,核心用 TypeScript 重寫
- VS Code:Microsoft 嘅程式碼編輯器
學習 TypeScript 嘅投資回報
短期收益:
- 減少除錯時間
- 提高程式碼質量
- 更好嘅開發體驗
長期收益:
- 更容易維護嘅程式碼
- 團隊協作更順暢
- 職業發展機會增加
實際例子:函式類型安全
1// JavaScript 函式 - 不清楚參數類型
2function greetJS(name, age) {
3 return `Hello ${name}, you are ${age} years old`;
4}
5
6// TypeScript 函式 - 清楚知道參數類型
7function greetTS(name: string, age: number): string {
8 return `Hello ${name}, you are ${age} years old`;
9}
10
11// 更複雜嘅例子:處理用戶資料
12interface User {
13 id: number;
14 name: string;
15 email: string;
16 isActive: boolean;
17}
18
19function processUser(user: User): string {
20 if (!user.isActive) {
21 return `User ${user.name} is inactive`;
22 }
23 return `Processing user: ${user.name} (${user.email})`;
24}
25
26// 使用時,編輯器會檢查物件結構
27const user: User = {
28 id: 1,
29 name: "小明",
30 email: "[email protected]",
31 isActive: true
32};
33
34console.log(processUser(user));🎯 互動練習 2:體驗類型錯誤檢測
3. TypeScript 嘅基本類型
TypeScript 有幾種基本類型,我哋先認識最常用嘅:
1// 基本類型範例
2let myString: string = "Hello"; // 字串
3let myNumber: number = 42; // 數字
4let myBoolean: boolean = true; // 布林值
5let myArray: number[] = [1, 2, 3, 4, 5]; // 數字陣列詳細類型介紹
1. 基本類型(Primitive Types)
字串(string)
1let firstName: string = "小明";
2let lastName: string = '李';
3let fullName: string = `${firstName} ${lastName}`; // 模板字串數字(number)
1let decimal: number = 6;
2let hex: number = 0xf00d; // 十六進制
3let binary: number = 0b1010; // 二進制
4let octal: number = 0o744; // 八進制
5let big: number = 100_000_000; // 數字分隔符布林值(boolean)
1let isDone: boolean = false;
2let isActive: boolean = true;2. 陣列類型(Array Types)
1// 兩種寫法都可以
2let list1: number[] = [1, 2, 3];
3let list2: Array<number> = [1, 2, 3];
4
5// 字串陣列
6let fruits: string[] = ["蘋果", "橙", "香蕉"];
7
8// 混合類型陣列(使用 union types)
9let mixed: (string | number)[] = ["hello", 42, "world"];3. 特殊類型
any - 任何類型
1let notSure: any = 4;
2notSure = "maybe a string instead";
3notSure = false; // 都可以,但失去了類型檢查void - 無返回值
1function warnUser(): void {
2 console.log("This is my warning message");
3}null 同 undefined
1let u: undefined = undefined;
2let n: null = null;4. 物件類型(Object Types)
基本物件
1let person: { name: string; age: number } = {
2 name: "小華",
3 age: 25
4};介面(Interface)
1interface Student {
2 id: number;
3 name: string;
4 grade: number;
5 isActive?: boolean; // 可選屬性
6}
7
8let student: Student = {
9 id: 1,
10 name: "小明",
11 grade: 85
12 // isActive 係可選嘅,可以唔提供
13};5. 函式類型(Function Types)
1// 函式聲明
2function add(x: number, y: number): number {
3 return x + y;
4}
5
6// 函式表達式
7let myAdd = function(x: number, y: number): number {
8 return x + y;
9};
10
11// 箭頭函式
12let myAdd2 = (x: number, y: number): number => x + y;
13
14// 函式類型變數
15let myAddFunc: (x: number, y: number) => number;
16myAddFunc = add;6. 聯合類型(Union Types)
1// 變數可以係多種類型之一
2let id: string | number;
3id = "ABC123"; // 可以
4id = 123; // 也可以
5// id = true; // 錯誤:boolean 唔係允許嘅類型
6
7function printId(id: string | number) {
8 if (typeof id === "string") {
9 // 喺呢個區塊,TypeScript 知道 id 係 string
10 console.log(id.toUpperCase());
11 } else {
12 // 喺呢個區塊,TypeScript 知道 id 係 number
13 console.log(id.toFixed(2));
14 }
15}7. 類型別名(Type Aliases)
1// 為複雜類型創建別名
2type StringOrNumber = string | number;
3type User = {
4 id: number;
5 name: string;
6 email: string;
7};
8
9let userId: StringOrNumber = "user123";
10let currentUser: User = {
11 id: 1,
12 name: "小明",
13 email: "[email protected]"
14};類型推斷(Type Inference)
TypeScript 好聰明,好多時候唔需要明確指定類型:
1// TypeScript 會自動推斷類型
2let message = "Hello"; // 推斷為 string
3let count = 42; // 推斷為 number
4let isReady = true; // 推斷為 boolean
5
6// 函式返回值也會被推斷
7function getLength(s: string) {
8 return s.length; // 推斷返回 number
9}類型斷言(Type Assertions)
有時候你比 TypeScript 更清楚某個值嘅類型:
1// 使用 as 語法
2let someValue: any = "this is a string";
3let strLength: number = (someValue as string).length;
4
5// 或者使用尖括號語法(但喺 JSX 中唔建議)
6let strLength2: number = (<string>someValue).length;🎯 互動練習 3:建立你嘅個人資料
1// 參考答案(你嘅答案可能會不同,呢個只係範例)
2let name: string = "小明";
3let age: number = 18;
4let isStudent: boolean = true;
5let hobbies: string[] = ["睇書", "打機", "聽音樂"];
6
7// 顯示個人資料
8console.log("=== 個人資料 ===");
9console.log("姓名:" + name);
10console.log("年齡:" + age);
11console.log("係學生:" + isStudent);
12console.log("興趣:" + hobbies.join(", "));重點:
- 每個變數都要符合指定嘅類型
string要用引號包住number直接寫數字boolean只能係true或false- 陣列用方括號
[]包住元素
4. 函式同類型
函式係程式設計嘅重要部分,TypeScript 可以幫我哋確保函式嘅輸入同輸出都係正確嘅類型。
1// 函式類型範例
2function add(a: number, b: number): number {
3 return a + b;
4}
5
6function sayHello(name: string): string {
7 return "Hello, " + name + "!";
8}🎯 互動練習 4:完成函式實作
1// 正確答案
2function add(a: number, b: number): number {
3 return a + b; // 返回兩個數字嘅和
4}
5
6function greet(name: string): string {
7 return "Hello, " + name + "!"; // 返回問候語
8}
9
10function introduce(name: string, age: number): string {
11 return name + "今年" + age + "歲"; // 返回介紹語句
12}
13
14// 測試你嘅函式(請勿修改下面嘅測試程式碼)
15console.log("5 + 3 = " + add(5, 3));
16console.log(greet("小明"));
17console.log(introduce("小華", 20));重點:
- 函式要返回正確嘅類型
add函式做數學加法greet函式組合字串introduce函式將名字同年齡組合成句子
5. 綜合練習
🎯 互動練習 5:寵物資料管理
1// 正確答案
2let petName: string = "小白"; // 寵物名字
3let petType: string = "貓"; // 寵物類型
4let petAge: number = 3; // 寵物年齡
5
6function introducePet(name: string, type: string, age: number): string {
7 return "我嘅寵物係一隻叫做" + name + "嘅" + type + ",佢今年" + age + "歲";
8}
9
10function describePet(name: string, type: string): string {
11 return name + "係一隻可愛嘅" + type;
12}
13
14// 測試你嘅程式(請勿修改下面嘅測試程式碼)
15console.log("=== 寵物資料 ===");
16console.log(introducePet(petName, petType, petAge));
17console.log(describePet(petName, petType));重點:
- 變數值要完全符合預期輸出
- 函式要準確組合字串
- 注意中文字符同標點符號
- 函式參數嘅順序要正確
6. TypeScript 開發環境同工具
TypeScript Playground 介紹
TypeScript Playground 係一個線上工具,你可以喺瀏覽器直接試寫 TypeScript 程式碼。
Playground 嘅好處:
- 唔需要安裝任何軟件
- 即時睇到編譯結果
- 可以分享程式碼俾其他人
- 有豐富嘅範例可以學習
你可以喺 TypeScript Playground 試試。
本地開發環境設置
1. 安裝 Node.js 同 npm
1# 檢查是否已安裝
2node --version
3npm --version2. 安裝 TypeScript
1# 全域安裝
2npm install -g typescript
3
4# 檢查安裝
5tsc --version3. 創建 TypeScript 專案
1# 創建專案資料夾
2mkdir my-typescript-project
3cd my-typescript-project
4
5# 初始化 npm 專案
6npm init -y
7
8# 創建 TypeScript 配置檔案
9tsc --init4. 基本專案結構
1my-typescript-project/
2├── src/
3│ ├── index.ts
4│ └── utils/
5│ └── helpers.ts
6├── dist/ # 編譯後嘅 JavaScript 檔案
7├── node_modules/
8├── package.json
9└── tsconfig.json # TypeScript 配置tsconfig.json 配置
1{
2 "compilerOptions": {
3 "target": "ES2020", // 編譯目標
4 "module": "commonjs", // 模組系統
5 "outDir": "./dist", // 輸出目錄
6 "rootDir": "./src", // 源碼目錄
7 "strict": true, // 嚴格模式
8 "esModuleInterop": true, // ES 模組互操作
9 "skipLibCheck": true, // 跳過庫檔案檢查
10 "forceConsistentCasingInFileNames": true
11 },
12 "include": ["src/**/*"], // 包含嘅檔案
13 "exclude": ["node_modules", "dist"]
14}常用編輯器同擴展
Visual Studio Code
- TypeScript Hero:自動導入管理
- Prettier:程式碼格式化
- ESLint:程式碼檢查
- Auto Rename Tag:自動重命名標籤
WebStorm
- 內建 TypeScript 支援
- 智能重構
- 強大嘅除錯功能
TypeScript 最佳實踐
1. 命名約定
1// 變數同函式:camelCase
2let userName = "小明";
3function getUserInfo() { }
4
5// 類別同介面:PascalCase
6class UserManager { }
7interface UserData { }
8
9// 常數:UPPER_SNAKE_CASE
10const MAX_RETRY_COUNT = 3;
11
12// 類型別名:PascalCase
13type UserRole = "admin" | "user" | "guest";2. 使用嚴格模式
1// 啟用嚴格模式可以捕獲更多錯誤
2// tsconfig.json 中設置 "strict": true
3
4// 避免使用 any
5let data: any = getData(); // ❌ 不好
6let data: UserData = getData(); // ✅ 好
7
8// 處理可能為 null 嘅值
9function processUser(user: User | null) {
10 if (user) {
11 // 安全地使用 user
12 console.log(user.name);
13 }
14}3. 善用類型守衛(Type Guards)
1function isString(value: any): value is string {
2 return typeof value === "string";
3}
4
5function processValue(value: string | number) {
6 if (isString(value)) {
7 // TypeScript 知道 value 係 string
8 console.log(value.toUpperCase());
9 } else {
10 // TypeScript 知道 value 係 number
11 console.log(value.toFixed(2));
12 }
13}4. 使用泛型(Generics)
1// 創建可重用嘅函式
2function identity<T>(arg: T): T {
3 return arg;
4}
5
6let output1 = identity<string>("myString");
7let output2 = identity<number>(100);
8
9// 泛型介面
10interface ApiResponse<T> {
11 data: T;
12 status: number;
13 message: string;
14}
15
16type UserResponse = ApiResponse<User>;
17type ProductResponse = ApiResponse<Product>;常見錯誤同解決方法
1. 類型錯誤
1// 錯誤:Type 'string' is not assignable to type 'number'
2let age: number = "25"; // ❌
3
4// 解決:確保類型匹配
5let age: number = 25; // ✅
6let ageString: string = "25"; // ✅2. 空值錯誤
1// 錯誤:Object is possibly 'null'
2function getUser(): User | null { /* ... */ }
3let user = getUser();
4console.log(user.name); // ❌
5
6// 解決:檢查空值
7let user = getUser();
8if (user) {
9 console.log(user.name); // ✅
10}3. 模組導入錯誤
1// 錯誤:Cannot find module
2import { helper } from "./helper"; // ❌ 缺少副檔名
3
4// 解決:正確嘅導入路徑
5import { helper } from "./helper.js"; // ✅🎯 互動練習 6:自由創作
1function calculator(a: number, b: number, operation: string): number {
2 if (operation === "+") return a + b;
3 if (operation === "-") return a - b;
4 if (operation === "*") return a * b;
5 if (operation === "/") return a / b;
6 return 0;
7}
8
9console.log("10 + 5 =", calculator(10, 5, "+"));
10console.log("10 - 5 =", calculator(10, 5, "-"));
11console.log("10 * 5 =", calculator(10, 5, "*"));
12console.log("10 / 5 =", calculator(10, 5, "/"));1let studentName: string = "小華";
2let mathScore: number = 85;
3let englishScore: number = 92;
4let averageScore: number = (mathScore + englishScore) / 2;
5
6function getGrade(score: number): string {
7 if (score >= 90) return "A";
8 if (score >= 80) return "B";
9 if (score >= 70) return "C";
10 return "D";
11}
12
13console.log(`${studentName}嘅平均分:${averageScore}`);
14console.log(`等級:${getGrade(averageScore)}`);
15console.log(`數學:${mathScore} (${getGrade(mathScore)})`);
16console.log(`英文:${englishScore} (${getGrade(englishScore)})`);1let hero: string = "勇者";
2let monster: string = "惡龍";
3let weapon: string = "神劍";
4let location: string = "魔法森林";
5
6function createStory(h: string, m: string, w: string, l: string): string {
7 return `從前有個${h},佢喺${l}遇到了${m}。經過激烈戰鬥,${h}用${w}打敗了${m},拯救了世界!`;
8}
9
10function createCharacter(name: string, level: number, hp: number): string {
11 return `角色:${name},等級:${level},血量:${hp}`;
12}
13
14console.log("=== 冒險故事 ===");
15console.log(createStory(hero, monster, weapon, location));
16console.log(createCharacter(hero, 50, 100));7. 知識檢查
🎯 互動練習 7:知識測驗
1// TypeScript 知識測驗 - 正確答案
2let answer1: string = "B"; // TypeScript 係 JavaScript 嘅超集
3let answer2: string = "A"; // TypeScript 嘅主要優勢係提供類型檢查
4let answer3: string = "B"; // TypeScript 最終會編譯成 JavaScript 程式碼
5
6// 顯示答案(請勿修改下面嘅程式碼)
7console.log("第1題答案:" + answer1);
8console.log("第2題答案:" + answer2);
9console.log("第3題答案:" + answer3);重點:
- TypeScript 係 JavaScript 嘅超集,唔係全新語言
- 主要優勢係類型檢查,幫助發現錯誤
- 最終會編譯成普通嘅 JavaScript 程式碼
總結
今日學到嘅重點
- TypeScript 係 JavaScript 嘅超集:所有 JavaScript 程式碼都係有效嘅 TypeScript 程式碼
- 類型註解:用
: type嘅方式指定變數類型 - 基本類型:
string、number、boolean、陣列等 - 函式類型:可以指定參數同返回值嘅類型
- 類型安全:TypeScript 可以喺寫程式碼時就發現錯誤
課後建議
- 去 TypeScript Playground 試下今日學嘅內容
- 試下將一啲簡單嘅 JavaScript 程式碼加上類型註解
- 觀察編輯器點樣提供更好嘅提示
- 重複做上面嘅互動練習,直到完全理解
下一課預告
下一課我哋會學習:
- 如何設置 TypeScript 開發環境
- 編譯 TypeScript 程式碼
- 基本嘅專案結構
- 更多實用嘅類型功能
恭喜你完成第一課! 🎉
你已經踏出學習 TypeScript 嘅第一步。記住,學習程式設計最重要係多練習,唔好怕犯錯。每個錯誤都係學習嘅機會!