[{"data":1,"prerenderedAt":1875},["ShallowReactive",2],{"blog:\u002Fblog\u002Fnuxt\u002Fglobal-type":3},{"id":4,"title":5,"author":6,"body":7,"category":1862,"date":1863,"description":1864,"draft":1865,"extension":1866,"image":1867,"meta":1868,"navigation":96,"path":1869,"seo":1870,"series":1867,"seriesOrder":1867,"seriesTitle":1867,"stem":1871,"tags":1872,"updatedAt":1867,"__hash__":1874},"blog\u002Fblog\u002Fnuxt\u002Fglobal-type.md","在 Nuxt 專案中優雅處理 null 與 undefined","charles",{"type":8,"value":9,"toc":1843},"minimark",[10,14,25,28,46,53,62,69,159,165,173,176,441,444,450,456,460,463,822,826,832,1070,1074,1077,1190,1194,1674,1678,1696,1707,1720,1729,1734,1743,1751,1775,1778,1784,1787,1807,1810,1827,1839],[11,12,13],"p",{},"在 Nuxt 專案 (及其他使用 TypeScript 的專案) 中，你一定遇過這些惱人的錯誤：",[11,15,16,20,21,24],{},[17,18,19],"code",{},"null is not an object","、",[17,22,23],{},"undefined is not assignable","。",[11,26,27],{},"尤其在處理 API、DOM 或使用者輸入時，「空值」幾乎無所不在。",[29,30,31],"blockquote",{},[11,32,33,37,38,41,42,45],{},[34,35,36],"strong",{},"空值處理定義","：本文所指的「空值」包含 ",[17,39,40],{},"null"," 和 ",[17,43,44],{},"undefined"," 兩種情況，這是 JavaScript\u002FTypeScript 開發中最常見的空值狀態。",[11,47,48,49,52],{},"如果每次都明確標註可能為空值 (",[17,50,51],{},"null | undefined",") 的型別，程式碼將變得冗長、重複，且容易產生 Typo，進而降低維護效率。",[54,55,57,58,61],"h2",{"id":56},"解決方案maybet-型別","解決方案：",[17,59,60],{},"Maybe\u003CT>"," 型別",[11,63,64,65,68],{},"在 Nuxt 專案中建立 ",[17,66,67],{},"\u002Ftypes\u002Fglobal.d.ts"," 檔案：",[70,71,76],"pre",{"className":72,"code":73,"language":74,"meta":75,"style":75},"language-typescript shiki shiki-themes material-theme-lighter github-light github-dark","export {};\n\ndeclare global {\n  type Maybe\u003CT> = T | null | undefined;\n}\n","typescript","",[17,77,78,91,98,112,153],{"__ignoreMap":75},[79,80,83,87],"span",{"class":81,"line":82},"line",1,[79,84,86],{"class":85},"sVHd0","export",[79,88,90],{"class":89},"sP7_E"," {};\n",[79,92,94],{"class":81,"line":93},2,[79,95,97],{"emptyLinePlaceholder":96},true,"\n",[79,99,101,105,109],{"class":81,"line":100},3,[79,102,104],{"class":103},"sbsja","declare",[79,106,108],{"class":107},"su5hD"," global ",[79,110,111],{"class":89},"{\n",[79,113,115,118,122,125,128,131,135,138,141,145,147,150],{"class":81,"line":114},4,[79,116,117],{"class":103},"  type",[79,119,121],{"class":120},"sbgvK"," Maybe",[79,123,124],{"class":89},"\u003C",[79,126,127],{"class":120},"T",[79,129,130],{"class":89},">",[79,132,134],{"class":133},"smGrS"," =",[79,136,137],{"class":120}," T",[79,139,140],{"class":133}," |",[79,142,144],{"class":143},"sZMiF"," null",[79,146,140],{"class":133},[79,148,149],{"class":143}," undefined",[79,151,152],{"class":89},";\n",[79,154,156],{"class":81,"line":155},5,[79,157,158],{"class":89},"}\n",[11,160,161,162,164],{},"有了 ",[17,163,60],{},"，空值處理就變得一致且明確，錯誤更容易在編譯時期被發現。",[166,167,169,170,172],"h3",{"id":168},"為什麼需要-maybet","為什麼需要 ",[17,171,60],{},"？",[11,174,175],{},"在 TypeScript 開發中，以下情況經常會產生型別錯誤：",[70,177,179],{"className":72,"code":178,"language":74,"meta":75,"style":75},"\u002F\u002F ❌ 這些都會產生型別錯誤\nconst user: User = null; \u002F\u002F API 回應可能為空值\nconst found: User = users.find((u) => u.id === 3); \u002F\u002F find() 可能回傳空值\nconst element: HTMLElement = document.querySelector(\".btn\"); \u002F\u002F DOM 查詢可能為空值\n\n\u002F\u002F ✅ 使用 Maybe\u003CT> 正確處理空值\nconst user: Maybe\u003CUser> = null;\nconst found: Maybe\u003CUser> = users.find((u) => u.id === 3) ?? null;\nconst element: Maybe\u003CHTMLElement> = document.querySelector(\".btn\");\n",[17,180,181,187,213,273,314,318,324,348,403],{"__ignoreMap":75},[79,182,183],{"class":81,"line":82},[79,184,186],{"class":185},"sutJx","\u002F\u002F ❌ 這些都會產生型別錯誤\n",[79,188,189,192,196,199,202,204,207,210],{"class":81,"line":93},[79,190,191],{"class":103},"const",[79,193,195],{"class":194},"s_hVV"," user",[79,197,198],{"class":133},":",[79,200,201],{"class":120}," User",[79,203,134],{"class":133},[79,205,144],{"class":206},"s39Yj",[79,208,209],{"class":89},";",[79,211,212],{"class":185}," \u002F\u002F API 回應可能為空值\n",[79,214,215,217,220,222,224,226,229,232,236,239,241,245,248,251,254,256,259,262,266,268,270],{"class":81,"line":100},[79,216,191],{"class":103},[79,218,219],{"class":194}," found",[79,221,198],{"class":133},[79,223,201],{"class":120},[79,225,134],{"class":133},[79,227,228],{"class":107}," users",[79,230,231],{"class":89},".",[79,233,235],{"class":234},"sGLFI","find",[79,237,238],{"class":107},"(",[79,240,238],{"class":89},[79,242,244],{"class":243},"s99_P","u",[79,246,247],{"class":89},")",[79,249,250],{"class":103}," =>",[79,252,253],{"class":107}," u",[79,255,231],{"class":89},[79,257,258],{"class":107},"id ",[79,260,261],{"class":133},"===",[79,263,265],{"class":264},"srdBf"," 3",[79,267,247],{"class":107},[79,269,209],{"class":89},[79,271,272],{"class":185}," \u002F\u002F find() 可能回傳空值\n",[79,274,275,277,280,282,285,287,290,292,295,297,301,305,307,309,311],{"class":81,"line":114},[79,276,191],{"class":103},[79,278,279],{"class":194}," element",[79,281,198],{"class":133},[79,283,284],{"class":120}," HTMLElement",[79,286,134],{"class":133},[79,288,289],{"class":107}," document",[79,291,231],{"class":89},[79,293,294],{"class":234},"querySelector",[79,296,238],{"class":107},[79,298,300],{"class":299},"sjJ54","\"",[79,302,304],{"class":303},"s_sjI",".btn",[79,306,300],{"class":299},[79,308,247],{"class":107},[79,310,209],{"class":89},[79,312,313],{"class":185}," \u002F\u002F DOM 查詢可能為空值\n",[79,315,316],{"class":81,"line":155},[79,317,97],{"emptyLinePlaceholder":96},[79,319,321],{"class":81,"line":320},6,[79,322,323],{"class":185},"\u002F\u002F ✅ 使用 Maybe\u003CT> 正確處理空值\n",[79,325,327,329,331,333,335,337,340,342,344,346],{"class":81,"line":326},7,[79,328,191],{"class":103},[79,330,195],{"class":194},[79,332,198],{"class":133},[79,334,121],{"class":120},[79,336,124],{"class":89},[79,338,339],{"class":120},"User",[79,341,130],{"class":89},[79,343,134],{"class":133},[79,345,144],{"class":206},[79,347,152],{"class":89},[79,349,351,353,355,357,359,361,363,365,367,369,371,373,375,377,379,381,383,385,387,389,391,393,396,399,401],{"class":81,"line":350},8,[79,352,191],{"class":103},[79,354,219],{"class":194},[79,356,198],{"class":133},[79,358,121],{"class":120},[79,360,124],{"class":89},[79,362,339],{"class":120},[79,364,130],{"class":89},[79,366,134],{"class":133},[79,368,228],{"class":107},[79,370,231],{"class":89},[79,372,235],{"class":234},[79,374,238],{"class":107},[79,376,238],{"class":89},[79,378,244],{"class":243},[79,380,247],{"class":89},[79,382,250],{"class":103},[79,384,253],{"class":107},[79,386,231],{"class":89},[79,388,258],{"class":107},[79,390,261],{"class":133},[79,392,265],{"class":264},[79,394,395],{"class":107},") ",[79,397,398],{"class":133},"??",[79,400,144],{"class":206},[79,402,152],{"class":89},[79,404,406,408,410,412,414,416,419,421,423,425,427,429,431,433,435,437,439],{"class":81,"line":405},9,[79,407,191],{"class":103},[79,409,279],{"class":194},[79,411,198],{"class":133},[79,413,121],{"class":120},[79,415,124],{"class":89},[79,417,418],{"class":120},"HTMLElement",[79,420,130],{"class":89},[79,422,134],{"class":133},[79,424,289],{"class":107},[79,426,231],{"class":89},[79,428,294],{"class":234},[79,430,238],{"class":107},[79,432,300],{"class":299},[79,434,304],{"class":303},[79,436,300],{"class":299},[79,438,247],{"class":107},[79,440,152],{"class":89},[11,442,443],{},"接下來我們看看實際專案中如何應用這個型別。",[54,445,447,448,172],{"id":446},"常見場景中該怎麼用-maybet","常見場景中，該怎麼用 ",[17,449,60],{},[11,451,452,453,455],{},"以下我們整理了 ",[17,454,60],{}," 在常見開發場景中的實務用法，搭配 Nuxt 與 Composition API，使其更具可讀性與維護性：",[166,457,459],{"id":458},"_1-api-回傳可能為-null","1. API 回傳可能為 null？",[11,461,462],{},"在處理 API 回應時，資料常常可能不存在或為空：",[70,464,468],{"className":465,"code":466,"language":467,"meta":75,"style":75},"language-vue shiki shiki-themes material-theme-lighter github-light github-dark","\u003Cscript setup lang=\"ts\">\ninterface User {\n  id: number;\n  name: string;\n  avatar?: string;\n}\n\n\u002F\u002F 使用 Maybe\u003CT> 明確表示 API 可能回傳空值\nconst { data: currentUser } = await useFetch\u003CMaybe\u003CUser>>(\"\u002Fapi\u002Fuser\u002Fme\");\n\n\u002F\u002F 安全地使用資料\nconst username = computed(() => currentUser?.name ?? \"訪客\");\nconst userAvatar = computed(() => currentUser?.avatar ?? \"\u002Fdefault-avatar.png\");\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Ch1>歡迎，{{ username }}\u003C\u002Fh1>\n    \u003CUserProfile v-if=\"currentUser\" :user=\"currentUser\" \u002F>\n    \u003CLoginPrompt v-else \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n","vue",[17,469,470,498,508,521,533,545,549,553,558,609,614,620,662,700,710,715,725,736,756,790,803,813],{"__ignoreMap":75},[79,471,472,474,478,482,485,488,490,493,495],{"class":81,"line":82},[79,473,124],{"class":89},[79,475,477],{"class":476},"sQzsp","script",[79,479,481],{"class":480},"s9AJx"," setup",[79,483,484],{"class":480}," lang",[79,486,487],{"class":89},"=",[79,489,300],{"class":299},[79,491,492],{"class":303},"ts",[79,494,300],{"class":299},[79,496,497],{"class":89},">\n",[79,499,500,503,505],{"class":81,"line":93},[79,501,502],{"class":103},"interface",[79,504,201],{"class":120},[79,506,507],{"class":89}," {\n",[79,509,510,514,516,519],{"class":81,"line":100},[79,511,513],{"class":512},"sucvu","  id",[79,515,198],{"class":133},[79,517,518],{"class":143}," number",[79,520,152],{"class":89},[79,522,523,526,528,531],{"class":81,"line":114},[79,524,525],{"class":512},"  name",[79,527,198],{"class":133},[79,529,530],{"class":143}," string",[79,532,152],{"class":89},[79,534,535,538,541,543],{"class":81,"line":155},[79,536,537],{"class":512},"  avatar",[79,539,540],{"class":133},"?:",[79,542,530],{"class":143},[79,544,152],{"class":89},[79,546,547],{"class":81,"line":320},[79,548,158],{"class":89},[79,550,551],{"class":81,"line":326},[79,552,97],{"emptyLinePlaceholder":96},[79,554,555],{"class":81,"line":350},[79,556,557],{"class":185},"\u002F\u002F 使用 Maybe\u003CT> 明確表示 API 可能回傳空值\n",[79,559,560,562,565,568,570,573,576,578,581,584,586,589,591,593,596,598,600,603,605,607],{"class":81,"line":405},[79,561,191],{"class":103},[79,563,564],{"class":89}," {",[79,566,567],{"class":512}," data",[79,569,198],{"class":89},[79,571,572],{"class":194}," currentUser",[79,574,575],{"class":89}," }",[79,577,134],{"class":133},[79,579,580],{"class":85}," await",[79,582,583],{"class":234}," useFetch",[79,585,124],{"class":89},[79,587,588],{"class":120},"Maybe",[79,590,124],{"class":89},[79,592,339],{"class":120},[79,594,595],{"class":89},">>",[79,597,238],{"class":107},[79,599,300],{"class":299},[79,601,602],{"class":303},"\u002Fapi\u002Fuser\u002Fme",[79,604,300],{"class":299},[79,606,247],{"class":107},[79,608,152],{"class":89},[79,610,612],{"class":81,"line":611},10,[79,613,97],{"emptyLinePlaceholder":96},[79,615,617],{"class":81,"line":616},11,[79,618,619],{"class":185},"\u002F\u002F 安全地使用資料\n",[79,621,623,625,628,630,633,635,638,640,642,645,648,650,653,656,658,660],{"class":81,"line":622},12,[79,624,191],{"class":103},[79,626,627],{"class":194}," username",[79,629,134],{"class":133},[79,631,632],{"class":234}," computed",[79,634,238],{"class":107},[79,636,637],{"class":89},"()",[79,639,250],{"class":103},[79,641,572],{"class":107},[79,643,644],{"class":89},"?.",[79,646,647],{"class":107},"name ",[79,649,398],{"class":133},[79,651,652],{"class":299}," \"",[79,654,655],{"class":303},"訪客",[79,657,300],{"class":299},[79,659,247],{"class":107},[79,661,152],{"class":89},[79,663,665,667,670,672,674,676,678,680,682,684,687,689,691,694,696,698],{"class":81,"line":664},13,[79,666,191],{"class":103},[79,668,669],{"class":194}," userAvatar",[79,671,134],{"class":133},[79,673,632],{"class":234},[79,675,238],{"class":107},[79,677,637],{"class":89},[79,679,250],{"class":103},[79,681,572],{"class":107},[79,683,644],{"class":89},[79,685,686],{"class":107},"avatar ",[79,688,398],{"class":133},[79,690,652],{"class":299},[79,692,693],{"class":303},"\u002Fdefault-avatar.png",[79,695,300],{"class":299},[79,697,247],{"class":107},[79,699,152],{"class":89},[79,701,703,706,708],{"class":81,"line":702},14,[79,704,705],{"class":89},"\u003C\u002F",[79,707,477],{"class":476},[79,709,497],{"class":89},[79,711,713],{"class":81,"line":712},15,[79,714,97],{"emptyLinePlaceholder":96},[79,716,718,720,723],{"class":81,"line":717},16,[79,719,124],{"class":89},[79,721,722],{"class":476},"template",[79,724,497],{"class":89},[79,726,728,731,734],{"class":81,"line":727},17,[79,729,730],{"class":89},"  \u003C",[79,732,733],{"class":476},"div",[79,735,497],{"class":89},[79,737,739,742,745,747,750,752,754],{"class":81,"line":738},18,[79,740,741],{"class":89},"    \u003C",[79,743,744],{"class":476},"h1",[79,746,130],{"class":89},[79,748,749],{"class":107},"歡迎，{{ username }}",[79,751,705],{"class":89},[79,753,744],{"class":476},[79,755,497],{"class":89},[79,757,759,761,764,767,769,771,774,776,779,781,783,785,787],{"class":81,"line":758},19,[79,760,741],{"class":89},[79,762,763],{"class":476},"UserProfile",[79,765,766],{"class":480}," v-if",[79,768,487],{"class":89},[79,770,300],{"class":299},[79,772,773],{"class":303},"currentUser",[79,775,300],{"class":299},[79,777,778],{"class":480}," :user",[79,780,487],{"class":89},[79,782,300],{"class":299},[79,784,773],{"class":303},[79,786,300],{"class":299},[79,788,789],{"class":89}," \u002F>\n",[79,791,793,795,798,801],{"class":81,"line":792},20,[79,794,741],{"class":89},[79,796,797],{"class":476},"LoginPrompt",[79,799,800],{"class":480}," v-else",[79,802,789],{"class":89},[79,804,806,809,811],{"class":81,"line":805},21,[79,807,808],{"class":89},"  \u003C\u002F",[79,810,733],{"class":476},[79,812,497],{"class":89},[79,814,816,818,820],{"class":81,"line":815},22,[79,817,705],{"class":89},[79,819,722],{"class":476},[79,821,497],{"class":89},[166,823,825],{"id":824},"_2-陣列查找結果可能為空","2. 陣列查找結果可能為空？",[11,827,828,831],{},[17,829,830],{},"Array.find()"," 方法經常會回傳空值：",[70,833,835],{"className":72,"code":834,"language":74,"meta":75,"style":75},"const products = ref\u003CProduct[]>([...]);\nconst productId = ref(3);\n\n\u002F\u002F 使用 Maybe\u003CT> 處理可能的空值\nconst selectedProduct: Ref\u003CMaybe\u003CProduct>> = ref(\n  products.value.find(p => p.id === productId.value) ?? null\n);\n\nconst productInfo = computed(() =>\n  selectedProduct.value\n    ? `${selectedProduct.value.name} - ${selectedProduct.value.price}`\n    : '找不到商品'\n);\n",[17,836,837,870,890,894,899,928,969,975,979,997,1007,1050,1064],{"__ignoreMap":75},[79,838,839,841,844,846,849,851,854,857,859,862,865,868],{"class":81,"line":82},[79,840,191],{"class":103},[79,842,843],{"class":194}," products",[79,845,134],{"class":133},[79,847,848],{"class":234}," ref",[79,850,124],{"class":89},[79,852,853],{"class":120},"Product",[79,855,856],{"class":107},"[]",[79,858,130],{"class":89},[79,860,861],{"class":107},"([",[79,863,864],{"class":133},"...",[79,866,867],{"class":107},"])",[79,869,152],{"class":89},[79,871,872,874,877,879,881,883,886,888],{"class":81,"line":93},[79,873,191],{"class":103},[79,875,876],{"class":194}," productId",[79,878,134],{"class":133},[79,880,848],{"class":234},[79,882,238],{"class":107},[79,884,885],{"class":264},"3",[79,887,247],{"class":107},[79,889,152],{"class":89},[79,891,892],{"class":81,"line":100},[79,893,97],{"emptyLinePlaceholder":96},[79,895,896],{"class":81,"line":114},[79,897,898],{"class":185},"\u002F\u002F 使用 Maybe\u003CT> 處理可能的空值\n",[79,900,901,903,906,908,911,913,915,917,919,921,923,925],{"class":81,"line":155},[79,902,191],{"class":103},[79,904,905],{"class":194}," selectedProduct",[79,907,198],{"class":133},[79,909,910],{"class":120}," Ref",[79,912,124],{"class":89},[79,914,588],{"class":120},[79,916,124],{"class":89},[79,918,853],{"class":120},[79,920,595],{"class":89},[79,922,134],{"class":133},[79,924,848],{"class":234},[79,926,927],{"class":107},"(\n",[79,929,930,933,935,938,940,942,944,946,948,951,953,955,957,959,961,964,966],{"class":81,"line":320},[79,931,932],{"class":107},"  products",[79,934,231],{"class":89},[79,936,937],{"class":107},"value",[79,939,231],{"class":89},[79,941,235],{"class":234},[79,943,238],{"class":107},[79,945,11],{"class":243},[79,947,250],{"class":103},[79,949,950],{"class":107}," p",[79,952,231],{"class":89},[79,954,258],{"class":107},[79,956,261],{"class":133},[79,958,876],{"class":107},[79,960,231],{"class":89},[79,962,963],{"class":107},"value) ",[79,965,398],{"class":133},[79,967,968],{"class":206}," null\n",[79,970,971,973],{"class":81,"line":326},[79,972,247],{"class":107},[79,974,152],{"class":89},[79,976,977],{"class":81,"line":350},[79,978,97],{"emptyLinePlaceholder":96},[79,980,981,983,986,988,990,992,994],{"class":81,"line":405},[79,982,191],{"class":103},[79,984,985],{"class":194}," productInfo",[79,987,134],{"class":133},[79,989,632],{"class":234},[79,991,238],{"class":107},[79,993,637],{"class":89},[79,995,996],{"class":103}," =>\n",[79,998,999,1002,1004],{"class":81,"line":611},[79,1000,1001],{"class":107},"  selectedProduct",[79,1003,231],{"class":89},[79,1005,1006],{"class":107},"value\n",[79,1008,1009,1012,1015,1018,1020,1022,1024,1027,1030,1033,1036,1038,1040,1042,1044,1047],{"class":81,"line":616},[79,1010,1011],{"class":133},"    ?",[79,1013,1014],{"class":299}," `${",[79,1016,1017],{"class":107},"selectedProduct",[79,1019,231],{"class":299},[79,1021,937],{"class":107},[79,1023,231],{"class":299},[79,1025,1026],{"class":107},"name",[79,1028,1029],{"class":299},"}",[79,1031,1032],{"class":303}," - ",[79,1034,1035],{"class":299},"${",[79,1037,1017],{"class":107},[79,1039,231],{"class":299},[79,1041,937],{"class":107},[79,1043,231],{"class":299},[79,1045,1046],{"class":107},"price",[79,1048,1049],{"class":299},"}`\n",[79,1051,1052,1055,1058,1061],{"class":81,"line":622},[79,1053,1054],{"class":133},"    :",[79,1056,1057],{"class":299}," '",[79,1059,1060],{"class":303},"找不到商品",[79,1062,1063],{"class":299},"'\n",[79,1065,1066,1068],{"class":81,"line":664},[79,1067,247],{"class":107},[79,1069,152],{"class":89},[166,1071,1073],{"id":1072},"_3-dom-查詢可能回傳空值","3. DOM 查詢可能回傳空值？",[11,1075,1076],{},"DOM 查詢方法可能回傳空值：",[70,1078,1080],{"className":72,"code":1079,"language":74,"meta":75,"style":75},"\u002F\u002F 使用 Maybe\u003CT> 處理可能的空值\nconst button: Maybe\u003CHTMLButtonElement> = document.querySelector(\"#submit-btn\");\n\n\u002F\u002F 安全地操作 DOM 元素\nconst handleClick = () => {\n  button?.setAttribute(\"disabled\", \"true\");\n};\n",[17,1081,1082,1086,1125,1129,1134,1151,1185],{"__ignoreMap":75},[79,1083,1084],{"class":81,"line":82},[79,1085,898],{"class":185},[79,1087,1088,1090,1093,1095,1097,1099,1102,1104,1106,1108,1110,1112,1114,1116,1119,1121,1123],{"class":81,"line":93},[79,1089,191],{"class":103},[79,1091,1092],{"class":194}," button",[79,1094,198],{"class":133},[79,1096,121],{"class":120},[79,1098,124],{"class":89},[79,1100,1101],{"class":120},"HTMLButtonElement",[79,1103,130],{"class":89},[79,1105,134],{"class":133},[79,1107,289],{"class":107},[79,1109,231],{"class":89},[79,1111,294],{"class":234},[79,1113,238],{"class":107},[79,1115,300],{"class":299},[79,1117,1118],{"class":303},"#submit-btn",[79,1120,300],{"class":299},[79,1122,247],{"class":107},[79,1124,152],{"class":89},[79,1126,1127],{"class":81,"line":100},[79,1128,97],{"emptyLinePlaceholder":96},[79,1130,1131],{"class":81,"line":114},[79,1132,1133],{"class":185},"\u002F\u002F 安全地操作 DOM 元素\n",[79,1135,1136,1138,1142,1144,1147,1149],{"class":81,"line":155},[79,1137,191],{"class":103},[79,1139,1141],{"class":1140},"sfCm-"," handleClick",[79,1143,134],{"class":133},[79,1145,1146],{"class":89}," ()",[79,1148,250],{"class":103},[79,1150,507],{"class":89},[79,1152,1153,1156,1158,1161,1164,1166,1169,1171,1174,1176,1179,1181,1183],{"class":81,"line":320},[79,1154,1155],{"class":107},"  button",[79,1157,644],{"class":89},[79,1159,1160],{"class":234},"setAttribute",[79,1162,238],{"class":1163},"skxfh",[79,1165,300],{"class":299},[79,1167,1168],{"class":303},"disabled",[79,1170,300],{"class":299},[79,1172,1173],{"class":89},",",[79,1175,652],{"class":299},[79,1177,1178],{"class":303},"true",[79,1180,300],{"class":299},[79,1182,247],{"class":1163},[79,1184,152],{"class":89},[79,1186,1187],{"class":81,"line":326},[79,1188,1189],{"class":89},"};\n",[166,1191,1193],{"id":1192},"_4-非同步資料載入可能為空","4. 非同步資料載入可能為空？",[70,1195,1197],{"className":465,"code":1196,"language":467,"meta":75,"style":75},"\u003Cscript setup lang=\"ts\">\n\u002F\u002F 使用 Maybe\u003CT> 表示載入狀態\nconst posts: Ref\u003CMaybe\u003CBlogPost[]>> = ref(null);\nconst error: Ref\u003CMaybe\u003Cstring>> = ref(null);\n\nconst fetchPosts = async () => {\n  try {\n    const { data: response } = await useFetch\u003CBlogPost[]>(\"\u002Fapi\u002Fposts\");\n    posts.value = response.value;\n  } catch (err) {\n    error.value = \"載入失敗\";\n    posts.value = null;\n  }\n};\n\nconst postCount = computed(() => posts.value?.length ?? 0);\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv v-if=\"posts && posts.length > 0\">\n    \u003Cp>共 {{ postCount }} 篇文章\u003C\u002Fp>\n    \u003Carticle v-for=\"post in posts\" :key=\"post.id\">\n      \u003Ch2>{{ post.title }}\u003C\u002Fh2>\n    \u003C\u002Farticle>\n  \u003C\u002Fdiv>\n  \u003Cdiv v-else-if=\"error\">{{ error }}\u003C\u002Fdiv>\n  \u003Cdiv v-else>目前沒有文章\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[17,1198,1199,1219,1224,1260,1294,1298,1316,1323,1366,1385,1403,1423,1437,1442,1446,1450,1488,1496,1500,1508,1527,1544,1577,1596,1606,1615,1645,1665],{"__ignoreMap":75},[79,1200,1201,1203,1205,1207,1209,1211,1213,1215,1217],{"class":81,"line":82},[79,1202,124],{"class":89},[79,1204,477],{"class":476},[79,1206,481],{"class":480},[79,1208,484],{"class":480},[79,1210,487],{"class":89},[79,1212,300],{"class":299},[79,1214,492],{"class":303},[79,1216,300],{"class":299},[79,1218,497],{"class":89},[79,1220,1221],{"class":81,"line":93},[79,1222,1223],{"class":185},"\u002F\u002F 使用 Maybe\u003CT> 表示載入狀態\n",[79,1225,1226,1228,1231,1233,1235,1237,1239,1241,1244,1246,1248,1250,1252,1254,1256,1258],{"class":81,"line":100},[79,1227,191],{"class":103},[79,1229,1230],{"class":194}," posts",[79,1232,198],{"class":133},[79,1234,910],{"class":120},[79,1236,124],{"class":89},[79,1238,588],{"class":120},[79,1240,124],{"class":89},[79,1242,1243],{"class":120},"BlogPost",[79,1245,856],{"class":107},[79,1247,595],{"class":89},[79,1249,134],{"class":133},[79,1251,848],{"class":234},[79,1253,238],{"class":107},[79,1255,40],{"class":206},[79,1257,247],{"class":107},[79,1259,152],{"class":89},[79,1261,1262,1264,1267,1269,1271,1273,1275,1277,1280,1282,1284,1286,1288,1290,1292],{"class":81,"line":114},[79,1263,191],{"class":103},[79,1265,1266],{"class":194}," error",[79,1268,198],{"class":133},[79,1270,910],{"class":120},[79,1272,124],{"class":89},[79,1274,588],{"class":120},[79,1276,124],{"class":89},[79,1278,1279],{"class":143},"string",[79,1281,595],{"class":89},[79,1283,134],{"class":133},[79,1285,848],{"class":234},[79,1287,238],{"class":107},[79,1289,40],{"class":206},[79,1291,247],{"class":107},[79,1293,152],{"class":89},[79,1295,1296],{"class":81,"line":155},[79,1297,97],{"emptyLinePlaceholder":96},[79,1299,1300,1302,1305,1307,1310,1312,1314],{"class":81,"line":320},[79,1301,191],{"class":103},[79,1303,1304],{"class":1140}," fetchPosts",[79,1306,134],{"class":133},[79,1308,1309],{"class":103}," async",[79,1311,1146],{"class":89},[79,1313,250],{"class":103},[79,1315,507],{"class":89},[79,1317,1318,1321],{"class":81,"line":326},[79,1319,1320],{"class":85},"  try",[79,1322,507],{"class":89},[79,1324,1325,1328,1330,1332,1334,1337,1339,1341,1343,1345,1347,1349,1351,1353,1355,1357,1360,1362,1364],{"class":81,"line":350},[79,1326,1327],{"class":103},"    const",[79,1329,564],{"class":89},[79,1331,567],{"class":512},[79,1333,198],{"class":89},[79,1335,1336],{"class":194}," response",[79,1338,575],{"class":89},[79,1340,134],{"class":133},[79,1342,580],{"class":85},[79,1344,583],{"class":234},[79,1346,124],{"class":89},[79,1348,1243],{"class":120},[79,1350,856],{"class":1163},[79,1352,130],{"class":89},[79,1354,238],{"class":1163},[79,1356,300],{"class":299},[79,1358,1359],{"class":303},"\u002Fapi\u002Fposts",[79,1361,300],{"class":299},[79,1363,247],{"class":1163},[79,1365,152],{"class":89},[79,1367,1368,1371,1373,1375,1377,1379,1381,1383],{"class":81,"line":405},[79,1369,1370],{"class":107},"    posts",[79,1372,231],{"class":89},[79,1374,937],{"class":107},[79,1376,134],{"class":133},[79,1378,1336],{"class":107},[79,1380,231],{"class":89},[79,1382,937],{"class":107},[79,1384,152],{"class":89},[79,1386,1387,1390,1393,1396,1399,1401],{"class":81,"line":611},[79,1388,1389],{"class":89},"  }",[79,1391,1392],{"class":85}," catch",[79,1394,1395],{"class":1163}," (",[79,1397,1398],{"class":107},"err",[79,1400,395],{"class":1163},[79,1402,111],{"class":89},[79,1404,1405,1408,1410,1412,1414,1416,1419,1421],{"class":81,"line":616},[79,1406,1407],{"class":107},"    error",[79,1409,231],{"class":89},[79,1411,937],{"class":107},[79,1413,134],{"class":133},[79,1415,652],{"class":299},[79,1417,1418],{"class":303},"載入失敗",[79,1420,300],{"class":299},[79,1422,152],{"class":89},[79,1424,1425,1427,1429,1431,1433,1435],{"class":81,"line":622},[79,1426,1370],{"class":107},[79,1428,231],{"class":89},[79,1430,937],{"class":107},[79,1432,134],{"class":133},[79,1434,144],{"class":206},[79,1436,152],{"class":89},[79,1438,1439],{"class":81,"line":664},[79,1440,1441],{"class":89},"  }\n",[79,1443,1444],{"class":81,"line":702},[79,1445,1189],{"class":89},[79,1447,1448],{"class":81,"line":712},[79,1449,97],{"emptyLinePlaceholder":96},[79,1451,1452,1454,1457,1459,1461,1463,1465,1467,1469,1471,1473,1475,1478,1481,1484,1486],{"class":81,"line":717},[79,1453,191],{"class":103},[79,1455,1456],{"class":194}," postCount",[79,1458,134],{"class":133},[79,1460,632],{"class":234},[79,1462,238],{"class":107},[79,1464,637],{"class":89},[79,1466,250],{"class":103},[79,1468,1230],{"class":107},[79,1470,231],{"class":89},[79,1472,937],{"class":107},[79,1474,644],{"class":89},[79,1476,1477],{"class":194},"length",[79,1479,1480],{"class":133}," ??",[79,1482,1483],{"class":264}," 0",[79,1485,247],{"class":107},[79,1487,152],{"class":89},[79,1489,1490,1492,1494],{"class":81,"line":727},[79,1491,705],{"class":89},[79,1493,477],{"class":476},[79,1495,497],{"class":89},[79,1497,1498],{"class":81,"line":738},[79,1499,97],{"emptyLinePlaceholder":96},[79,1501,1502,1504,1506],{"class":81,"line":758},[79,1503,124],{"class":89},[79,1505,722],{"class":476},[79,1507,497],{"class":89},[79,1509,1510,1512,1514,1516,1518,1520,1523,1525],{"class":81,"line":792},[79,1511,730],{"class":89},[79,1513,733],{"class":476},[79,1515,766],{"class":480},[79,1517,487],{"class":89},[79,1519,300],{"class":299},[79,1521,1522],{"class":303},"posts && posts.length > 0",[79,1524,300],{"class":299},[79,1526,497],{"class":89},[79,1528,1529,1531,1533,1535,1538,1540,1542],{"class":81,"line":805},[79,1530,741],{"class":89},[79,1532,11],{"class":476},[79,1534,130],{"class":89},[79,1536,1537],{"class":107},"共 {{ postCount }} 篇文章",[79,1539,705],{"class":89},[79,1541,11],{"class":476},[79,1543,497],{"class":89},[79,1545,1546,1548,1551,1554,1556,1558,1561,1563,1566,1568,1570,1573,1575],{"class":81,"line":815},[79,1547,741],{"class":89},[79,1549,1550],{"class":476},"article",[79,1552,1553],{"class":480}," v-for",[79,1555,487],{"class":89},[79,1557,300],{"class":299},[79,1559,1560],{"class":303},"post in posts",[79,1562,300],{"class":299},[79,1564,1565],{"class":480}," :key",[79,1567,487],{"class":89},[79,1569,300],{"class":299},[79,1571,1572],{"class":303},"post.id",[79,1574,300],{"class":299},[79,1576,497],{"class":89},[79,1578,1580,1583,1585,1587,1590,1592,1594],{"class":81,"line":1579},23,[79,1581,1582],{"class":89},"      \u003C",[79,1584,54],{"class":476},[79,1586,130],{"class":89},[79,1588,1589],{"class":107},"{{ post.title }}",[79,1591,705],{"class":89},[79,1593,54],{"class":476},[79,1595,497],{"class":89},[79,1597,1599,1602,1604],{"class":81,"line":1598},24,[79,1600,1601],{"class":89},"    \u003C\u002F",[79,1603,1550],{"class":476},[79,1605,497],{"class":89},[79,1607,1609,1611,1613],{"class":81,"line":1608},25,[79,1610,808],{"class":89},[79,1612,733],{"class":476},[79,1614,497],{"class":89},[79,1616,1618,1620,1622,1625,1627,1629,1632,1634,1636,1639,1641,1643],{"class":81,"line":1617},26,[79,1619,730],{"class":89},[79,1621,733],{"class":476},[79,1623,1624],{"class":480}," v-else-if",[79,1626,487],{"class":89},[79,1628,300],{"class":299},[79,1630,1631],{"class":303},"error",[79,1633,300],{"class":299},[79,1635,130],{"class":89},[79,1637,1638],{"class":107},"{{ error }}",[79,1640,705],{"class":89},[79,1642,733],{"class":476},[79,1644,497],{"class":89},[79,1646,1648,1650,1652,1654,1656,1659,1661,1663],{"class":81,"line":1647},27,[79,1649,730],{"class":89},[79,1651,733],{"class":476},[79,1653,800],{"class":480},[79,1655,130],{"class":89},[79,1657,1658],{"class":107},"目前沒有文章",[79,1660,705],{"class":89},[79,1662,733],{"class":476},[79,1664,497],{"class":89},[79,1666,1668,1670,1672],{"class":81,"line":1667},28,[79,1669,705],{"class":89},[79,1671,722],{"class":476},[79,1673,497],{"class":89},[54,1675,1677],{"id":1676},"常見-typescript-錯誤與解決方案","常見 TypeScript 錯誤與解決方案",[1679,1680,1681],"ul",{},[1682,1683,1684,1685,1688,1689,1691,1692,1695],"li",{},"空值賦值錯誤：\n當你嘗試將 null 指派給一個非空型別 (例如 User) 時，會出現錯誤訊息：\n",[17,1686,1687],{},"Type 'null' is not assignable to type 'User'","\n解決方式是使用 ",[17,1690,60],{},"，將變數型別定義為 ",[17,1693,1694],{},"Maybe\u003CUser>","，讓 null 成為合法值：",[70,1697,1701],{"className":1698,"code":1699,"language":1700,"meta":75,"style":75},"language-typescript:line-numbers shiki shiki-themes material-theme-lighter github-light github-dark","const user: Maybe\u003CUser> = null;\n","typescript:line-numbers",[17,1702,1703],{"__ignoreMap":75},[79,1704,1705],{"class":81,"line":82},[79,1706,1699],{},[1679,1708,1709],{},[1682,1710,1711,1712,1715,1716,1719],{},"未定義賦值錯誤：\n當一個變數預期為 string，但實際上可能是 undefined 時，會出現：\n",[17,1713,1714],{},"Type 'undefined' is not assignable to type 'string'","\n你可以將該型別改成 ",[17,1717,1718],{},"Maybe\u003Cstring>","，或在賦值時使用空值合併運算子確保不會是 undefined：",[70,1721,1723],{"className":1698,"code":1722,"language":1700,"meta":75,"style":75},"const result: Maybe\u003Cstring> = value ?? null;\n",[17,1724,1725],{"__ignoreMap":75},[79,1726,1727],{"class":81,"line":82},[79,1728,1722],{},[1679,1730,1731],{},[1682,1732,1733],{},"可選屬性型別錯誤：\n當 API 回傳可能是陣列或 undefined，你想將其存入嚴格的陣列型別時，會出現：\nType 'User [] | undefined' is not assignable to type 'User []'\n利用 Maybe\u003CUser []> 可以包裝陣列，並允許 null 或 undefined：",[70,1735,1737],{"className":1698,"code":1736,"language":1700,"meta":75,"style":75},"const users: Maybe\u003CUser[]> = response.data ?? null;\n",[17,1738,1739],{"__ignoreMap":75},[79,1740,1741],{"class":81,"line":82},[79,1742,1736],{},[1679,1744,1745],{},[1682,1746,1747,1748,1750],{},"函式缺少回傳錯誤：\n如果函式簽名指定回傳某型別，但在所有分支沒有明確回傳值，會出現：\nFunction lacks ending return statement\n這時候將回傳型別設為 ",[17,1749,60],{}," 並確保所有分支有適當回傳值即可解決：",[70,1752,1754],{"className":1698,"code":1753,"language":1700,"meta":75,"style":75},"const getUserName = (id: number): Maybe\u003Cstring> => {\n  if (id === 0) return null;\n  \u002F\u002F 其他邏輯...\n};\n",[17,1755,1756,1761,1766,1771],{"__ignoreMap":75},[79,1757,1758],{"class":81,"line":82},[79,1759,1760],{},"const getUserName = (id: number): Maybe\u003Cstring> => {\n",[79,1762,1763],{"class":81,"line":93},[79,1764,1765],{},"  if (id === 0) return null;\n",[79,1767,1768],{"class":81,"line":100},[79,1769,1770],{},"  \u002F\u002F 其他邏輯...\n",[79,1772,1773],{"class":81,"line":114},[79,1774,1189],{},[54,1776,1777],{"id":1777},"總結",[11,1779,1780,1781,1783],{},"透過在 Nuxt 專案中定義 ",[17,1782,60],{}," 型別，我們獲得了：",[166,1785,1786],{"id":1786},"核心優勢",[1679,1788,1789,1795,1801],{},[1682,1790,1791,1794],{},[34,1792,1793],{},"型別安全","：編譯時期發現空值錯誤",[1682,1796,1797,1800],{},[34,1798,1799],{},"程式碼清晰","：明確表達資料可能為空值的意圖",[1682,1802,1803,1806],{},[34,1804,1805],{},"開發效率","：利用 Auto Import，無需重複定義",[166,1808,1809],{"id":1809},"常見應用",[1679,1811,1812,1815,1818,1821,1824],{},[1682,1813,1814],{},"API 回應處理",[1682,1816,1817],{},"陣列查找結果",[1682,1819,1820],{},"表單狀態管理",[1682,1822,1823],{},"DOM 元素操作",[1682,1825,1826],{},"非同步資料載入",[11,1828,1829,1831,1832,20,1835,1838],{},[17,1830,60],{}," 只是開始。你可以進一步探索 ",[17,1833,1834],{},"Result\u003CT, E>",[17,1836,1837],{},"Option\u003CT>"," 等進階型別模式，打造語意明確、錯誤彈性的業務邏輯型別系統。",[1840,1841,1842],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sQzsp, html code.shiki .sQzsp{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .s9AJx, html code.shiki .s9AJx{--shiki-light:#9C3EDA;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sucvu, html code.shiki .sucvu{--shiki-light:#E53935;--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sfCm-, html code.shiki .sfCm-{--shiki-light:#90A4AE;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":75,"searchDepth":100,"depth":100,"links":1844},[1845,1850,1857,1858],{"id":56,"depth":93,"text":1846,"children":1847},"解決方案：Maybe\u003CT> 型別",[1848],{"id":168,"depth":100,"text":1849},"為什麼需要 Maybe\u003CT>？",{"id":446,"depth":93,"text":1851,"children":1852},"常見場景中，該怎麼用 Maybe\u003CT>？",[1853,1854,1855,1856],{"id":458,"depth":100,"text":459},{"id":824,"depth":100,"text":825},{"id":1072,"depth":100,"text":1073},{"id":1192,"depth":100,"text":1193},{"id":1676,"depth":93,"text":1677},{"id":1777,"depth":93,"text":1777,"children":1859},[1860,1861],{"id":1786,"depth":100,"text":1786},{"id":1809,"depth":100,"text":1809},"Nuxt","2025-06-03","透過 Maybe\u003CT> 全域型別定義，在 Nuxt 專案中優雅地處理可能為 null 或 undefined 的值，提升型別安全和開發體驗。",false,"md",null,{},"\u002Fblog\u002Fnuxt\u002Fglobal-type",{"title":5,"description":1864},"blog\u002Fnuxt\u002Fglobal-type",[1862,1873],"TypeScript","tFBsPVSq_wQgvImGDIbcnQXtUdasr83Lpdx9yQCaOWI",1780512500676]