Vue 3 script setup defineProps 的坑

閱讀時間約 1 分鐘

問題

最近筆者在學習如何於 Vue 專案中使用 Apollo Graphql Client 從 API 獲取資料,由於資料來自 GraphqlZero ,結構較為複雜,筆者便跟著網路教學使用 codegen 工具自動化產生 TypeScript 型別定義。在某個元件中,需要使用 defineProps 這個 API 來傳遞 Post 這筆資料,於是很天真的在 <script setup> 裡面寫:


原以為可以輕易地使用自訂型別...

原以為可以輕易地使用自訂型別...

結果意想不到的事情發生了,竟然在 runtime 發生 ReferenceError 錯誤

What? TypeScript 跑到 runtime 了??

What? TypeScript 跑到 runtime 了??


推測原因

針對此問題,猜測原因有兩種可能:

  • 這是 Apollo Client 的坑
  • 這是 import type 的坑
  • 這是 Vue 在 TypeScript 的坑


於是我看了一下範例程式碼,發現自己在 Apollo Client 使用上應該是沒有錯誤。找了一下網路文章,也都沒有提到 Apollo Client 會造成 TypeScript 在 runtime 報錯的案例。


那麼,會不會是 import Post 這個型別時出了什麼差錯?於是我查了一下 TypeScript 關於 import type 寫法的說明:

裡面有提到可以在 tsconfig 裡面 用 "importsNotUsedAsValues" 這個屬性,來避免 type 被當成 JavaScript 變數處理。我修改了一下 tsconfig.app.json 檔案:

vite 和 Vue 官方把 tsconfig 拆成好幾份,足見 TS 有多麻煩

vite 和 Vue 官方把 tsconfig 拆成好幾份,足見 TS 有多麻煩


解決方式

以上嘗試都沒有改變結果,後來我逐行檢視,發現問題可能出在 defineProps 定義 post 的型別時:

raw-image

這裏是使用自訂義的型別,而非 Vue 官方提供的 String、Array、Object 等型別定義,問題是出在這嗎?

raw-image


在 Vue 文件的 <script setup> 一節中提到,雖然有支援自訂型別,但太過複雜的型別定義, Vue 可能還是會無法辨識,把它當作一般的 runtime 變數。讓我們來看看 Post 這個型別的內容吧。

如此複雜的型別定義

如此複雜的型別定義


於是,我想到既然 Post 是一個物件,若使用 Object 配合 TypeScript 的 as 做型別斷言,或許可以成功?

object as Post...總算解決型別定義問題

object as Post...總算解決型別定義問題


之後終於讓 TypeScript 把 Post 當成型別定義,不會在 runtime 報錯了。這個坑還真是深,且筆者還注意到,若在 defineProps 使用 Post [] ,不會有任何錯誤,可能 TypeScript 會讓它 fallback 為一般的陣列吧⋯⋯

3會員
5內容數
我是Sail,這裡主要分享一些自己覺得有趣的前端議題。
留言0
查看全部
發表第一個留言支持創作者!
你可能也想看
創作者要怎麼好好休息 + 避免工作過量?《黑貓創作報#4》午安,最近累不累? 這篇不是虛假的關心。而是《黑貓創作報》發行以來可能最重要的一篇。 是的,我們這篇講怎麼補充能量,也就是怎麼休息。
Thumbnail
avatar
黑貓老師
2024-06-29
防曬產品係數測試報告彙整(2024年)從2014年起,自己對於市售防曬產品的效能產生了濃厚的興趣。因為當時候發現不少產品的防曬係數其實標示是有問題的,像是原本應該是人體測試的SPF與PA數值,實際上沒有做,只用機器測試的數據來充當,但這兩者卻有很大的差異。像是防曬係數其實有強度、廣度與平均度三個面向需要一起判斷,但多數廠商並沒有完整標示
Thumbnail
avatar
邱品齊皮膚科醫師
2023-04-27
Vue3 - 在網頁上嵌入Google Map及設置圖釘的兩種方法這篇文章記錄了如何在網頁中使用<iframe>或套件vue3-google-map來實現Google Map呈現,並在上面設置圖釘。兩種方法的優缺點也有相關的說明。想要在網頁上加入Google Map及設置圖釘的讀者可以參考這篇文章。
Thumbnail
avatar
Moreene
2024-02-28
Vue3 筆記 | NuxtVue 筆記,Nuxt 簡介
Thumbnail
avatar
Jeremy Ho
2023-11-21
Vue3 筆記 | Vue 進階篇Vue3 筆記,指令進階篇
Thumbnail
avatar
Jeremy Ho
2023-11-13
Vue 3.2 defineEmits 用法父元件 傳遞方法使用@ <template>    ...    <Login @modalClose="modalClose"/> ... </template> <script setup>     const _modal = ref();     function m
avatar
Vic Lin
2023-08-13
Vue 3 自學筆記 - watch 的使用自學筆記 - Vue3 watch 的應用
Thumbnail
avatar
圈圈
2023-03-13
Vue 3.2 defineProps 用法父元件 傳遞變數時須加上冒號 子元件 接收props用法如下 本筆記參考: 1. https://www.netlify.com/blog/understanding-defineprops-and-defineemits-in-vue-3.2 2. https://juejin.cn/post/7
avatar
Vic Lin
2023-03-10
六角學院-2022冬季Vue 3 作品實戰班心得分享雖然距離上次Vue直播班課不到一年,但看到這次的課程有Pinia內容,手又不小心刷了魔法小卡(? 意識到自己的成長應該是可以輕鬆地串接API,畢竟去年也已經串到可以去烤串店了XD,就算是重新複習,還是可以從中獲得新的成長,而且發現到老師一年講的比一年還好,今年有很多觀念講得更清楚了! 可惜這次第六週
Thumbnail
avatar
王聖禮
2023-03-03
[3] Vue 專案架構專案建好了,那先來講 Vue 的專案架構 詳細內容很多,所以我挑重點講 public index.html public/index.html 是 Vue 頁面的 entry point,進入一個 Vue 頁面會先進 public/index.html,再套用 App.vue,最後才是進入你寫的 .
Thumbnail
avatar
張哲嘉
2022-10-05