iT邦幫忙

2024 iThome 鐵人賽

DAY 11
0
JavaScript

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

我推Day11 - TypeScript 除錯大法!破解隱藏錯誤,讓你寫出零Bug神級程式

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20240925/20124462BrGATvUruj.jpg


帶你深入了解常見 TypeScript 陷阱,逐步解密每一個錯誤背後的真相

嘿嘿,大家寫 TypeScript 是不是也常常踩雷呢?
其實 TypeScript 超好用,但那種突然冒出來的錯誤訊息,真的會讓人瞬間卡住啊!

不用怕,這篇就是你的救星!
我會帶你一起來破解那些搞得人頭昏腦脹的 TypeScript 錯誤,幫你解鎖各種「我哪有寫錯!」的迷之瞬間!

不管是神出鬼沒的 any 類型、還是奇怪的 never 錯誤,通通包在我身上!
就讓我們輕鬆搞定這些煩人的小bug,讓你的程式碼從此不再鬧脾氣!一起變更強吧~


程式碼

type Talk = {
  title: string,
  abstract: string,
  speaker: string
}

type TechEventBase = {
  title: string,
  description: string
  date: Date,
  capacity: number,
  rsvp: number,
  kind: EventKind
}

type Conference = TechEventBase & {
  location: string,
  price: number,
  talks: Talk[],
  kind: 'conference'
}

type Meetup = TechEventBase & {
  location: string,
  price: string,
  talks: Talk[],
  kind: 'meetup'
}

type Webinar = TechEventBase & {
  url: string,
  price?: number,
  talks: Talk,
  kind: 'webinar'
}

type TechEvent = Webinar | Conference | Meetup;

type EventKind =  'conference' | 'meetup' | 'webinar'

type UserEvents = {
  watching: TechEvent[],
  rsvp: TechEvent[],
  attended: TechEvent[],
  signedout: TechEvent[],
}

type UserEventCategory = 
  'watching' | 'rsvp' | 'attended' | 'signedoff'

function filterUserEvent(
  userEventList: UserEvents,
  category: UserEventCategory,
  filterKind?: EventKind
) {
  const filteredList = userEventList[category]
  if (filterKind) {
    return filteredList.filter(event =>
      event.kind === filterKind)
  }
  return filteredList
}

function getEventTeaser(event: TechEvent) {
  switch(event.kind) {
    case 'conference':
      return `${event.title} (Conference), ` + 
        `priced at ${event.price} USD`
    case 'meetup':
      return `${event.title} (Meetup), ` + 
        `hosted at ${event.location}`
    case 'webinar':
      return `${event.title} (Webinar), ` +
        `available online at ${event.url}`
    case 'hackathon':
      return `${event.title} (Hackathon)`
    default:
      throw new Error('Not sure what to do with that!')
  }
}

Errors in code

  • Element implicitly has an 'any' type because expression of type 'UserEventCategory' can't be used to index type 'UserEvents'. Property 'signedoff' does not exist on type 'UserEvents'.
  • Parameter 'event' implicitly has an 'any' type.
  • Type '"hackathon"' is not comparable to type '"conference" | "meetup" | "webinar"'.
  • Property 'title' does not exist on type 'never'.

調試 TypeScript 錯誤的教學

在這段程式碼中,我們遇到了一些常見的 TypeScript 錯誤。
這些錯誤若不修正,將影響程式的正常運行。
接下來,我將逐步解析每個錯誤的原因、如何解決,並提供修正後的程式碼。

1. 錯誤:UserEventCategory 類型的表達式無法用於索引類型 UserEvents,因此元素隱式具有 any 類型。

這個錯誤的根本原因是 TypeScript 無法確認 UserEventCategory 中的 category 參數可以安全地索引 UserEvents。這是因為 UserEventCategory 包含了 'signedoff',而 UserEvents 對應的鍵名其實是 'signedout'

解決方法:

  • UserEventCategory'signedoff' 修改為 'signedout',確保名稱對應一致。

修正後的程式碼:

type UserEventCategory = 'watching' | 'rsvp' | 'attended' | 'signedout';

2. 錯誤:參數 event 隱式具有 any 類型。

filterUserEvent 函式中,使用 filter 方法時,TypeScript 無法自動推斷 event 參數的類型,因此會預設為 any,這樣做容易引發類型安全問題。

解決方法:

  • 明確定義 filter 方法中的 event 參數類型為 TechEvent

修正後的程式碼:

function filterUserEvent(
  userEventList: UserEvents,
  category: UserEventCategory,
  filterKind?: EventKind
) {
  const filteredList = userEventList[category];
  if (filterKind) {
    return filteredList.filter((event: TechEvent) => 
      event.kind === filterKind);
  }
  return filteredList;
}

3. 錯誤:"hackathon" 無法與 "conference" | "meetup" | "webinar" 類型進行比較。

這個錯誤出現在 getEventTeaser 函式中的 switch 語句中,因為 'hackathon' 並不在 EventKind 類型定義中,且也未被任何 TechEvent 使用,因此類型不匹配。

解決方法:

  • 移除 switch 語句中的 'hackathon',確保處理的類型符合 EventKind 的定義。

修正後的程式碼:

function getEventTeaser(event: TechEvent) {
  switch(event.kind) {
    case 'conference':
      return `${event.title} (Conference), ` + 
        `priced at ${event.price} USD`;
    case 'meetup':
      return `${event.title} (Meetup), ` + 
        `hosted at ${event.location}`;
    case 'webinar':
      return `${event.title} (Webinar), ` +
        `available online at ${event.url}`;
    default:
      throw new Error('Not sure what to do with that!');
  }
}

4. 錯誤:屬性 'title' 不存在於 never 類型上。

這個錯誤是因為 TypeScript 無法確定 getEventTeaserevent 的正確類型,推斷結果為 never 類型。這通常是因為處理了不應該存在的類型(如 'hackathon'),導致 TypeScript 無法理解 event 的結構。

解決方法:

  • 確保 switch 案例匹配正確定義的類型,這樣就不會出現 never 類型錯誤。

總結小語

  1. 索引簽名不匹配:

    • TypeScript 在進行物件索引時,會嚴格檢查類型。
    • 如果索引值包含未出現在物件中的鍵名,會導致錯誤。調整類型名稱,使其對應,能確保程式的正確性。
  2. 明確定義類型:

    • 透過為函式參數明確定義類型,可以避免隱式 any,這樣能讓 TypeScript 的類型檢查機制發揮作用,保證程式的安全性和可讀性。
  3. Switch 案例的類型匹配:

    • switch 語句應只處理定義內的有效類型。如果加入未定義的類型,會導致 TypeScript 無法正確推斷類型,引發 never 錯誤。
  4. 正確處理類型:

    • 將程式碼類型與 TypeScript 的類型系統對齊,有助於編寫更易維護且少錯誤的程式碼,這也是使用 TypeScript 的一大優勢。

透過這些修正,程式碼會更符合 TypeScript 的嚴格類型系統,不僅提升開發體驗,還能在開發過程中及早發現問題,避免潛在的錯誤。

好啦,今天的 TypeScript 除錯小冒險就到這邊啦
希望看完之後,大家在面對那些奇奇怪怪的錯誤訊息時,不再感到手足無措。

別忘了,程式開發就是這樣,一步步踩坑、一步步成長,這才是進步的關鍵!
下次遇到 bug 就別怕了,拿出你的自信和技巧,把它當作練等升級的好機會!

Coding 這條路上,我們都在一起學習、一起變強,未來也會越來越厲害~
加油,寫出屬於自己的神級程式吧!💪🚀✨



上一篇
我推Day10 - TypeScript 函數多載 Function Overloading 的神奇力量!
下一篇
我推Day12 - 聯合類型大爆發!用 TypeScript 寫出全場最靈活的程式碼
系列文
我推的TypeScript 操作大全30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言