iT邦幫忙

2024 iThome 鐵人賽

DAY 13
0
JavaScript

我推的TypeScript 操作大全系列 第 13

我推Day13 - TypeScript 除錯教學:輕鬆搞定型別問題!

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20240927/20124462tyfr9omMA2.jpg


當 TypeScript 型別發脾氣,該怎麼辦?這篇文章教你輕鬆掌握泛型約束的秘訣,讓程式碼運行更穩健!🐱‍💻**

嘿嘿,小夥伴們,今天我們要來解決 TypeScript 的一個小小挑戰!
這次的錯誤來自於型別系統的衝突,尤其是當我們在檢查物件屬性時,TypeScript 有時會有點「任性」。不過別擔心,我們會一一解決,讓你不再踩坑!👀

本文目標:

  1. 理解程式碼中常見的型別錯誤訊息。
  2. 學會如何優化 TypeScript 型別檢查函式,讓程式更健壯。
  3. 提供具體解決方案及正確程式碼示例。

程式碼介紹

我們這段程式碼定義了兩組 URL 格式的物件:VideoFormatURLsSubtitleURLs,並搭配幾個用來檢查屬性是否存在的函式。
主要目的是確保在讀取或使用物件屬性時,是安全且可預期的。但執行時遇到一個有趣的錯誤,來看看是什麼吧!

type VideoFormatURLs = {
  format360p: URL,
  format480p: URL,
  format720p: URL,
  format1080p: URL
}

function isFormatAvailable(
  obj: VideoFormatURLs,
  key: string
): key is keyof VideoFormatURLs {
  return key in obj
}

declare const videoFormat: VideoFormatURLs

function loadFormat(format: string) {
  if(isAvailable(videoFormat, format)) {
    videoFormat[format].pathname.toUpperCase
  }
}

type SubtitleURLs = {
  english: URL,
  german: URL,
  french: URL
}

function isSubtitleAvailable(
  obj: SubtitleURLs,
  key: string
): key is keyof SubtitleURLs {
  return key in obj
}

function isAvailable<Obj>(
  obj: Obj,
  key: string | number | symbol
): key is keyof Obj {
  return key in obj
}

錯誤提示

Errors in code

  • Type 'Obj' is not assignable to type 'object'.

解讀錯誤訊息

這個錯誤告訴我們,isAvailable 函式中的泛型 Obj 沒有被明確限制為物件型別。
TypeScript 要求 keyof 的操作對象必須是一個物件類型,但我們的 Obj 缺少這樣的約束,導致編譯錯誤。

  • 錯誤分析:
    這個錯誤出現在 isAvailable 函式中。
    雖然我們使用 in 操作符來檢查屬性是否存在,但 TypeScript 對泛型類型不太放心。keyof 需要的是一個物件類型,而 Obj 並沒有被明確限制為物件型別,因此會噴這個錯誤。

解決步驟

  1. 問題定位: 檢查 isAvailable 函式簽名,發現 Obj 沒有被限制為物件類型。

  2. 解決方法: 在泛型 Obj 後添加 extends object,明確告訴 TypeScript 這是一個物件,避免型別錯誤。

我們需要告訴 TypeScript,Obj 一定是一個物件類型。只要稍微改寫一下函式簽名,讓泛型 Obj 確保它繼承自 object 就搞定啦!

修正後:

function isAvailable<Obj extends object>(  // 加上 extends object
  obj: Obj,
  key: string | number | symbol 
): key is keyof Obj {
  return key in obj
}

這樣一來,TypeScript 就知道 Obj 確實是物件了,不會再對我們使用 in 操作符吹毛求疵啦!


針對各函式的使用和最佳化:

  1. isFormatAvailableisSubtitleAvailable: 這兩個函式的目的是用來檢查某個特定格式或字幕是否存在於物件中。

  2. 當我們確定 key 是物件的屬性時,TypeScript 會自動推斷該屬性的型別,這樣代碼就更安全。

  3. 共用的 isAvailable 函式: 因為我們有多種不同的物件需要檢查屬性,所以使用泛型的方式來實現一個通用的 isAvailable 函式。

  4. 這樣可以減少重複程式碼,並保持更好的可讀性。

完整的修正後程式碼:

type VideoFormatURLs = {
  format360p: URL,
  format480p: URL,
  format720p: URL,
  format1080p: URL
}

function isFormatAvailable(
  obj: VideoFormatURLs,
  key: string
): key is keyof VideoFormatURLs {
  return key in obj
}

declare const videoFormat: VideoFormatURLs

function loadFormat(format: string) {
  if (isAvailable(videoFormat, format)) {
    videoFormat[format].pathname.toUpperCase()  // 別忘了呼叫函式
  }
}

type SubtitleURLs = {
  english: URL,
  german: URL, 
  french: URL
}

function isSubtitleAvailable(
  obj: SubtitleURLs,
  key: string
): key is keyof SubtitleURLs {
  return key in obj
}

function isAvailable<Obj extends object>(  // 修正泛型約束
  obj: Obj,
  key: string | number | symbol 
): key is keyof Obj {
  return key in obj
}

小貼士:

  1. 別忘了 ():在使用屬性的方法時,不要忘記加上 (),像是 toUpperCase(),少了這個小括號就只會拿到函式本身,結果當然不如預期啦!

  2. 類型限制是你的好朋友:為泛型加上約束,不僅是為了避免錯誤,也是對程式行為的自信保證哦!這麼一來,TypeScript 的型別檢查就能幫你避開更多潛在的問題。

演練區

TypeScript: TS Playground - An online editor for exploring TypeScript and JavaScript

試著在自己的 TypeScript 專案中應用這些技巧,透過調整型別和加強函式的安全性,來強化你的程式碼吧!


總結小語

  • 型別約束是保護你的好朋友:給泛型加上 extends object 來告訴 TypeScript 你的意圖,避免不必要的錯誤。
  • 記得加小括號 ():別忘記調用函數或方法時要加上小括號,避免出現未預期的錯誤。
  • 保持冷靜、逐步排查:遇到錯誤時,分析訊息,逐步排查問題,不要慌張。
  • 多實踐、多嘗試:實踐是最好的學習,自己動手做比什麼都管用!

這樣,你就能輕鬆掌握 TypeScript 的型別陷阱,變得更強大!相信自己,每一個 debug 都是邁向程式大神的重要一步!🚀


上一篇
我推Day12 - 聯合類型大爆發!用 TypeScript 寫出全場最靈活的程式碼
下一篇
我推Day14 - 偷師大法學到的 TypeScript 實戰祕技技巧
系列文
我推的TypeScript 操作大全30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言