💻 TypeScript 資深前端工程師面試與實戰指南
💡 前言:從寫程式到工程治理
資深工程師的價值,在於規劃與維護,而不只是寫程式。本指南涵蓋了 TypeScript 的基礎、進階應用、到解決大型專案中的效能與團隊協作難題。
🧠 基礎語法與型別系統:確保工程基石的穩固
✅ 暖身題與核心概念
| 題目編號 | 題目內容 | 預期回答深度與 資深實戰心法 |
| 1. | any、unknown、never 的差異與實戰場景。 | 經驗談: 永遠將從 API 獲取的未驗證資料視為 unknown,這是一個工程師對資料不確定性負責的態度。never 更是狀態機設計的 "安全鎖"。 |
| 2. | interface 與 type 的差異與情境選擇。 | 經驗談: 在 React/Vue 元件庫中,我通常會選擇 interface 來定義 Props,因為它的 宣告合併 (Declaration Merging) 特性允許使用者或第三方擴充這些 Props,提升元件的彈性與開放性。type 則專注於複雜的邏輯運算。 |
| 3. | 請寫出一個泛型函式,接收任意陣列並回傳其第一個元素,並確保回傳的元素型別與陣列元素型別一致。 | 關鍵: 泛型 T 確保輸入 T[] 和回傳 T 的型別連結。這是確保函式具備型別多樣性的基礎。 |
🧩 實戰應用與架構設計:用型別抽象業務邏輯
✅ 元件與型別抽象
| 題目編號 | 題目內容 | 預期回答深度與 資深實戰心法 |
| 4. | 如何在 React/Vue 專案中定義元件 Props 的型別?處理繼承與覆寫 HTML 元素原生屬性。 | React 心法: 務必使用 Omit<T, K> 排除原生屬性,避免使用者傳入自訂 onClick 導致與元件內部的 onClick 邏輯衝突。這確保了元件 API 的單純與可控性。 |
| 5. | 設計一個 FormField<T> 泛型元件,能根據傳入的 value 或 onChange 型別,自動推導並限制該元件的其他相關 Props。 | 挑戰心法: 這是考驗 Discriminated Unions (可識別聯集) 的實際應用。必須利用 條件型別 確保當 T 是 number 時,元件 Props 上的 type 屬性必須被限制為 "number",從根源上避免開發錯誤。 |
| 6. | 如何使用 TypeScript 實現一個安全的 API 呼叫封裝(例如 axios wrapper),確保輸入參數與成功/失敗的回傳資料都具備強型別? | 工程心法: 除了 TResponse 和 TParams,在實戰中我還會將 TError 和 AbortSignal (用於取消請求) 納入泛型考量。這樣能確保整個網路層的輸入、輸出、錯誤都具備強型別,極大提升除錯效率。 |
🧪 型別推論與進階技巧:駕馭複雜度
✅ 型別挑戰題
| 題目編號 | 題目內容 | 預期回答深度與 資深實戰心法 |
| 7. | 請解釋 keyof、typeof、infer、as const 的用途與差異,並舉例說明如何組合使用它們。 | 組合應用: keyof typeof 搭配 as const 是 Design Tokens 導出到程式碼時,確保型別精確的標準做法。infer 則是在處理複雜第三方函式的回傳型別時,用於提取其內部型別的利器。 |
| 8. | 如何定義一個型別,讓它只能接受某個 enum 或字串聯集的部分值,並在編譯時進行檢查? | 心法: 針對 enum,我會建議團隊避免使用 enum,而是使用 as const 的字面值聯集,搭配 Exclude<T, U> 進行精確的子集創建,避免 enum 帶來的潛在運行時問題。 |
| 9. | 請寫出一個 Utility Type Optional<T, K>,能將某個物件 T 中指定的屬性 K 變成可選 (Optional),但保留 T 中其他屬性的必選性。 | 關鍵: 必須熟練運用 Omit<T, K> 和 Partial<Pick<T, K>> 進行型別映射 (Type Mapping),這是處理複雜資料結構轉換的基礎能力。 |
🚀 效能與最佳化:大規模專案的維護之戰
✅ 型別最佳化與維護性
| 題目編號 | 題目內容 | 預期回答深度與 資深實戰心法 |
| 10. | 如何避免 TypeScript 型別過度複雜或難以維護?你有什麼命名或抽象策略? | 工程心法: 複雜型別必須拆解!我會規範型別定義不得超過 3-4 層嵌套。並強制使用 TSDoc 說明型別用途。Props、State、Schema 等後綴必須統一,提升團隊間的溝通效率。 |
| 11. | 你如何處理大型 Monorepo 中的型別共用與版本管理? | 架構心法: 隔離!將所有共用型別放入一個獨立的、零依賴的 @shared/types Package。在 tsconfig.json 中配置 paths 映射來優化解析速度,並使用 Monorepo 工具嚴格檢查循環依賴。 |
| 12. | TypeScript 編譯效能慢時,你會如何排查與優化? | 除錯心法: tsc --generateTrace 是我的第一步診斷工具。在實戰中,我發現很多效能問題來自於 skipLibCheck: false 導致編譯器不斷檢查 node_modules。其次是避免複雜的遞迴型別,它會讓編譯器陷入運算深淵。 |
🤝 團隊協作與型別治理:讓 TS 成為團隊助力
✅ 團隊實務題
| 題目編號 | 題目內容 | 預期回答深度與 資深實戰心法 |
| 13. | 你如何在團隊中推動 TypeScript adoption?有沒有漸進式導入的策略? | 推廣策略: 絕對不能一次到位!我的策略是:從測試開始導入 (風險最低,收益最高),接著型別化 API 服務層 (核心資料流)。對於舊程式,先使用 JSDoc 註解提供型別資訊,避免開發人員的恐懼。 |
| 14. | 如何設計一套型別 Lint 規則(例如搭配 ESLint + TypeScript)?請舉例說明一條你認為重要的規則。 | 治理規則: 最重要的是 @typescript-eslint/explicit-function-return-type。強制回傳型別能避免型別推論過度寬鬆,減少未來 Bug 的潛在空間。其他如 noImplicitAny 必須在導入後期才開啟。 |
| 15. | 當你發現某個型別設計不合理或難以擴充,你會如何 Refactor 並與團隊溝通? | 溝通心法: 提出 Refactor 時,必須先展示現有設計帶來的 "痛苦指數" (Pain Points)。重構時,使用 @deprecated 標註舊型別,並執行新舊型別並存的策略,給團隊足夠的時間平滑過渡。 |
💣 TypeScript 面試常見陷阱題庫 (Trap Repository)
經驗揭露:這些陷阱是 Bug 的溫床
| 陷阱編號 | 題目與程式碼 | 陷阱點與 資深解題心法 |
| 1. | any vs unknown 的陷阱:你會怎麼選擇 any 或 unknown? | 陷阱點: 誤以為 any 方便。 心法: unknown 是責任,強制處理不確定性;any 是逃避,將錯誤留給執行時。 |
| 3. | as const 的型別推論陷阱:const color = ['red', 'green', 'blue']; 是什麼型別? | 陷阱點: 忽略預設是寬鬆的 string[]。心法: 在定義配置常數、路由名稱等需要精確字面值的場景,一律使用 as const。 |
| 4. | keyof 與 typeof 的混淆:keyof typeof obj 是什麼意思? | 陷阱點: 混淆 typeof (拿值型別) 與 keyof (拿型別的鍵)。心法: 它是從 JS 值導出 TS 型別契約 的基本模式,務必熟練。 |
| 6. | Partial<T> 的陷阱:Partial<T> 是什麼? | 陷阱點: 忽略它將所有屬性都變成 optional,可能使既有的可選屬性變得更難管理。心法: 精確使用 Omit 和 Pick 來控制可選範圍,避免意外副作用。 |
| 7. | Record<K, T> 的誤用:Record<string, number> 是什麼意思? | 陷阱點: 誤用寬鬆的 string 作為鍵。心法: K 應使用字串字面值聯集。定義的越精確,型別系統能給你越多的保障。 |
| 10. | 型別守衛與 asserts:如何保證某個值是 string? | 陷阱點: 只知道傳統 is 守衛。心法: asserts 是終止程式碼執行的型別守衛,適用於檢查非空值或預期狀態。它能徹底消除不安全的 ! 運算子,提升程式碼的健壯性。 |
| 11. | 誤解 satisfies 的用途 | 陷阱點: 誤將 satisfies 當成 :。心法: satisfies 解決了 「嚴格檢查但不收窄型別」 的衝突。在定義配置物件時,它能讓你同時享受到 推論字面值型別 和 介面結構檢查 的雙重好處。 |
沒有留言:
張貼留言