因為未來工作長期會使用到Typescript,所以就趁這時候筆記一下與JS的差異方面。
過去在寫Vue3、Angular時有大量接觸Typescript,就趁這時間重溫一下。
- 賦值
JS 是動態型別 → 錯誤在執行時才發現
TS 是靜態型別 → 編譯時就檢查出錯,減少 bug
JS
1 | let age = 25; |
TS
1 | let age: number = 25; |
- 函數參數與回傳型別
TS 允許定義 參數型別 和 回傳型別,防止不合法輸入
TS
1 | function add(a: number, b: number): number { |
3.可選參數及預設值
TS 用 ? 宣告參數可選
搭配 nullish coalescing (??) 處理 null 或 undefined
1 | function greet(name?: string) { |
JS則是用||處理
JS
1 | function greet(name) { |
4.Interface
TS interface 能保證物件結構正確,JS 則只能在執行時才發現問題
TS
1 | interface User { |
5.Enum vs. Magic String
Enum 可集中管理常量並提供型別檢查,避免拼錯問題
TS
1 | enum Status { |
JS則無
JS
1 | const status = "success"; // Magic string,容易拼錯 |
6.參數多種型別檢查Union Types
TS:
1 | function printId(id: number | string) { |
- 泛型 (Generics)
any 會失去型別資訊
泛型保留型別,讓函數既安全又通用
TS:
1 | function identity<T>(arg: T): T { |
一般JS不好確認型別
JS:
1 | function identity(arg) { |
8.非空斷言與 Optional Chaining
?. 可安全存取深層屬性
搭配 ! 非空斷言在確定不為空時跳過檢查
TS:
1 | const user: any = {}; |
JS則無法
JS:
1 | const user = {}; |
- any vs. unknown
什麼時候用 any,什麼時候用 unknown?
JS:
1 | let value; // 無型別限制 |
any 跟 JS 一樣完全不檢查型別(危險)
unknown 要先檢查型別才可使用(安全)
TS:
1 | let value: unknown; |
- 類別 (Class) 的型別修飾符
JS 與 TS 在類別屬性可見性上的差異
JS:
1 | class Person { |
TS 提供 public(預設)、private、protected,可精確控制存取範圍
TS:
1 | class Person { |
- 型別別名(Type Alias)與複雜型別組合
大型專案中可以將複雜型別命名,方便重用與維護
TS:
1 | type OrderStatus = "pending" | "shipped" | "delivered"; |
- Intersection Types(交叉型別)合併資料結構
JS:
1 | // 只能動態合併物件 |
交叉型別在多個模組資料合併時很常用(特別是 Redux / API 結果整合)
TS:
1 | type Name = { name: string }; |
- 型別守衛(Type Guards)
JS
1 | function handle(val) { |
大型專案裡經常用自訂型別守衛來精準縮小型別範圍
TS
1 | function isFunction(value: unknown): value is Function { |
- 宣告檔(.d.ts)與第三方函式庫型別
JS:
1 | // 使用第三方庫時,無法獲得型別提示 |
大型專案幾乎都要用 .d.ts 來補齊沒有型別定義的第三方套件
TS:
1 | // @types/moment 提供型別定義 |
15.readonly 與 Immutable 資料結構
readonly 對大型專案的設定檔、常量物件非常重要
Typescript
1 | type Config = { |
- keyof 與型別安全的物件鍵名存取
JS
1 | function getProp(obj, key) { |
keyof 確保傳入的屬性名稱是物件中真實存在的鍵名
TS
1 | function getProp<T, K extends keyof T>(obj: T, key: K) { |
- Mapped Types(映射型別)
JS:
1 | // 只能手動定義每個屬性為可選 |
大型專案中 Partial、Required、Readonly 等都是 Mapped Types 的應用
TS:
1 | type User = { id: number; name: string; age: number }; |
- 模組與命名空間(Modules vs Namespaces)
JS:
1 | // 無型別檢查的全域污染 |
大型專案建議使用 ES Modules 搭配 TS 的型別系統管理命名與依賴
TS:
1 | // 使用模組系統 |
- 型別推斷與 as const
1 | const roles = ["admin", "user"]; |
as const 在定義固定字面值陣列、物件時非常有用(例如權限、狀態碼)
1 | const roles = ["admin", "user"] as const; |
- Non-null Assertion(非空斷言)與嚴格模式
JS:
1 | let el = document.getElementById("myDiv"); |
嚴格模式 (strictNullChecks) 在大型專案中很重要,可以提早發現 null/undefined 錯誤
TS:
1 | let el = document.getElementById("myDiv")!; |