iT邦幫忙

2024 iThome 鐵人賽

DAY 15
0
JavaScript

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

我推Day15 - 技術大神專屬!TypeScript JSON 處理術你一定要學!

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20240929/20124462iMmYR7CH5m.jpg

嘿嘿~今天來跟大家聊聊 TypeScript 裡的 JSON 型別處理
這可是個相當有趣又實用的話題,特別是當我們在處理物件序列化和反序列化時,這套「神奇的型別技巧」真的能夠幫助你寫出更安全、更乾淨的程式碼!


什麼是 JSON 型別處理?

你可能會問:「TypeScript 處理 JSON 不就是 JSON.stringifyJSON.parse 嗎?」嗯,雖然這是真的,但我們要進一步考慮型別安全!TypeScript 讓我們不僅僅能正確序列化/反序列化資料,還可以確保這些操作在編譯時就能夠型別正確地推斷資料的結構。這樣我們不會踩坑,也不用擔心序列化後的物件會跟原來長得不一樣!😂


TypeScript 的 JSONified 型別

讓我直接從程式碼開始講起!看看這段 TypeScript 代碼,它展示了如何處理物件中的 JSON 型別:

type JSONified<T> = 
  JSONifiedValue<T extends { toJSON(): infer U } ? U : T>;

這段程式碼的意思是,如果你的物件有 toJSON 方法,那我們就用它返回的型別來處理;如果沒有,則直接處理物件本身的型別。

這樣做的好處是什麼呢?假如我們有些物件(比如 Date)需要轉換成更簡單的格式,我們可以通過 toJSON() 來控制返回的值,讓序列化的物件格式化得更適合 JSON。

這樣就能避免把複雜的物件直接序列化,讓程式碼更簡潔!


JSONifiedValue 的魔法

接下來看看這個更具魔力的型別定義:

type JSONifiedValue<T> =
  T extends string | number | boolean | null ? T :
  T extends Function ? never :
  T extends Array<infer U> ? JSONifiedArray<U> :
  T extends object ? JSONifiedObject<T> : 
  never;

這裡的邏輯就有點細節了,但別擔心!我來幫你拆解:

  1. 基本型別處理stringnumberbooleannull 是直接支援的,沒問題。
  2. 函式無法序列化:JSON 中不允許函式,所以如果你想把 () => {} 這種函式直接變成 JSON,那可不行喔!這裡會返回 never,TypeScript 就會跳出來阻止你做錯事。
  3. 陣列型別處理:這是個更常見的情境,我們會用 Array<infer U> 來推導出陣列的元素型別,然後對每個元素進行遞歸處理。
  4. 物件型別處理:如果遇到一般的物件型別,我們會再進一步處理每個屬性,保證所有屬性都符合 JSON 規範。

問題來了:undefined 要怎麼辦?

JSON 不支援 undefined,那該怎麼辦?這裡我們用了一個很聰明的小技巧:

type UndefinedAsNull<T> = T extends undefined ? null : T;

我們把 undefined 轉換成 null,這樣當你有一些屬性可能是 undefined 的時候,它們會在序列化後變成 null,這樣就符合 JSON 標準了。是不是很聰明?!


常見的使用錯誤

這麼多技巧聽起來很強大,但在實際應用中也有幾個容易犯的小錯誤:

  1. 忘記處理 undefined:這是非常常見的問題,許多開發者在序列化物件時忽略了 undefined 無法被 JSON 表示。如果沒有像上面那樣進行 undefinednull 的轉換,序列化時會出現資料丟失的情況。

  2. 函式試圖進行序列化:很多時候我們不小心會把函式也一併序列化,導致 JSON.stringify 出錯。記得,函式是無法被序列化的,所以要特別注意!

  3. 對複雜物件缺少 toJSON():如果物件太複雜,記得使用 toJSON() 方法來格式化它的輸出,否則序列化後可能得到一個非常笨重的 JSON 結構,或者有些無法序列化的屬性會被直接丟掉。


小結與實際應用

總結來說,這些型別技巧讓我們可以輕鬆、安全地處理 TypeScript 中的 JSON 操作,保證型別正確並且不會踩到常見的 JSON 陷阱。

當然,這裡還有一個實用的 Serializer 類別,讓我們可以輕鬆地序列化和反序列化物件,像這樣:

class Serializer<T> {
  serialize(inp: T): string {
    return JSON.stringify(inp);
  }

  deserialize(inp: string): JSONified<T> {
    return JSON.parse(inp);
  }
}

有了這個類別,你可以確保你的物件在進行 JSON 操作時,型別完全正確,這對於大型專案非常有用。


總結小語

  • 型別安全的 JSON 操作:透過 JSONified 型別,確保物件在序列化和反序列化時符合 JSON 結構。

  • 處理 undefined:使用 UndefinedAsNullundefined 轉換為 null,避免 JSON 不支援 undefined 的問題。

  • 避免函式序列化:函式無法被序列化,要特別注意將其過濾掉,否則會導致錯誤。

  • Generator 函式與懶惰評估:使用 Generator 函式,按需生成資料,避免一次處理過多數據導致資源浪費。

  • 高級型別處理:利用 Pickinfer 等工具型別,優化物件的型別定義,使得 JSON 操作更加靈活與準確。


結語

希望這些 TypeScript 型別處理的小撇步能幫助你更順利地應對 JSON 相關的挑戰!
程式開發總是充滿了各種細節和挑戰,但只要掌握了正確的工具和技巧,很多問題都能迎刃而解~✨

記住,下一次寫 TypeScript 時,別忘了這些小技巧,讓你的程式碼更加優雅、更加安全!
Happy Coding~ 💻🚀


上一篇
我推Day14 - 偷師大法學到的 TypeScript 實戰祕技技巧
下一篇
我推Day16 - 深度解析 TypeScript 泛型與動態服務系統
系列文
我推的TypeScript 操作大全30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言