Vue 泛型元件,讓 TypeScript 更精確

更新於 2024/08/26閱讀時間約 8 分鐘
鱈魚的魚缸搬家了!新家文章皆有重新修訂,歡迎來新家看看喔。(´▽`ʃ♡ƪ)



大家好,我是鱈魚。(^∀^●)ノシ


Vue 3.3 終於新增了泛型元件(Generic Component),這讓我們可以在 TypeScript 環境中得到更準確的型別提示。ˋ( ° ▽、° )


這個泛型元件與 TypeScript 的 Generic 是同一個概念,不知道 Generic 的朋友可以先來來複習一下


甚麼?你說你沒有使用 TypeScript?抱歉浪費您 5 秒鐘,可以上一頁了。(>人<;)


或者在離開前路過文檔湊個熱鬧。(. ❛ ᴗ ❛.)


有使用 TypeScript 的朋友就讓我們一起繼續看下去吧。ლ(╹◡╹ლ)

來個 select

假設我需要一個綁定物件的 select,最常見的問題就是 modelValue 只能 any,如下:

SelectAny.vue

<script setup lang="ts">
...(省略其他程式碼)

interface Prop {
modelValue: any;
label?: string;
options: any[];
optionLabel?: (option: any) => string;
/** 是否多選 */
multiple?: boolean;
}

...
</script>
...

v-model 這個糖

忘記元件怎麼實現 v-model 的朋友們別擔心,讓我們複習一下。


💡 Vue 3.4 開始可以使用 defineModel,不過與此文主題無關,所以我們先使用經典寫法。


v-model 只是一個語法糖,實際上的程式碼如下(文檔)。

<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>

<template>
<input
:value="props.modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</template>

modelValue 就是用來表示預設綁定值的變數,讓我們回到剛剛的 any。


所以現在就算我們的 modelValue 與 options 的型別不同,或者 multiple 為 true,而 modelValue 卻沒有給矩陣時,都不會有任何錯誤提示。

<script setup lang="ts">
...
import SelectAny from './SelectAny.vue';

const options: User[] = [
{ name: '鱈魚', price: 10000 },
{ name: '章魚', price: 100 }
];

const anyDatum = ref<{ age: number }>();
const seletedAnyDatum = ref<User>();
</script>

<template>
<!-- anyDatum 與 option 型別不同 -->
<SelectAny v-model="anyDatum" :options="options" :option-label="getLabel" />

<!-- modelValue 沒有給矩陣 -->
<SelectAny v-model="seletedAnyDatum" multiple :options="options" :option-label="getLabel" />
</template>

畢竟是 any 嘛。(˘・_・˘)


加上泛型

如果加上元件泛型就不會有以上問題了。

SelectGeneric.vue

<script 
setup
lang="ts"
generic="ModelValue, Multiple extends boolean"
>
...

interface Prop {
modelValue: Multiple extends true ? ModelValue[] : ModelValue;
label?: string;
options: ModelValue[];
optionLabel?: (option: any) => string;
/** 是否多選 */
multiple?: Multiple;
}

...
</script>
...

除了 modelValue、options 有泛型 ModelValue 外,我們還加上 multiple 判斷,如果為 true,則 modelValue 為 ModelValue[],否則為 ModelValue。


這樣子就可以達成以下效果:

  • modelValue 與 options 型別不同時警告,
  • multiple 為 true 時,如果 modelValue 沒有提供矩陣時發出警告。
<script setup lang="ts">
...
import SelectGeneric from './SelectGeneric.vue';

const options: User[] = [
{ name: '鱈魚', price: 10000 },
{ name: '章魚', price: 100 }
];

const anyDatum = ref<{ age: number }>();
const seletedGenericDatum = ref<User>();
const seletedGenericData = ref<User[]>([]);
</script>

<template>
<!-- Type '{ age: number; }' is not assignable to type 'User | User[]'.ts(2322) -->
<SelectGeneric v-model="anyDatum" :options="options" :option-label="getLabel" />

<!-- Type 'User' is not assignable to type 'User[]'.ts(2322) -->
<SelectGeneric v-model="seletedGenericDatum" multiple :options="options" :option-label="getLabel" />

<!-- 正確 -->
<SelectGeneric v-model="seletedGenericData" multiple :options="options" :option-label="getLabel" />
</template>

TypeScript 成功重返光榮。o((>ω< ))o


文章到此結束了,感謝您的閱讀,以上程式碼可以在此取得。

有其他想法請不吝告訴我,鱈魚感謝您!(o゜▽゜)o☆

avatar-img
17會員
14內容數
各種鱈魚滾鍵盤的雜紀
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
鱈魚的魚缸 的其他內容
大家好,我是鱈魚。(。・∀・)ノ゙ 最近看到大家討論取得 API 時機,有許多人都提到「一定要」或者「習慣」,在 onMounted 這個 hook 內呼叫 API 取得資料。 其實這也沒不好,但是也沒什麼好處就是了。(。・ω・。)
pipe 代表函數式程式設計中的概念,利用多個功能結合在一起,資料依序通過每個功能進行處理。文章中介紹了 pipe 的優點、兩個等效的程式碼比較以及 remeda 套件的使用。詳細介紹了使用 pipe 的好處,並提供了多個相關的例子,展示了 pipe 可讀性的提升。
大家好,我是鱈魚。(。・∀・)ノ゙ 最近看到大家討論取得 API 時機,有許多人都提到「一定要」或者「習慣」,在 onMounted 這個 hook 內呼叫 API 取得資料。 其實這也沒不好,但是也沒什麼好處就是了。(。・ω・。)
pipe 代表函數式程式設計中的概念,利用多個功能結合在一起,資料依序通過每個功能進行處理。文章中介紹了 pipe 的優點、兩個等效的程式碼比較以及 remeda 套件的使用。詳細介紹了使用 pipe 的好處,並提供了多個相關的例子,展示了 pipe 可讀性的提升。
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
在 Vue 中,watch是用於進行數據監聽的,可以用來響應式的監聽資料的變化並執行相應的操作。本文介紹watch功能,並透過實際範例讓你更好的理解。
Thumbnail
在 Vue 中,methods和computed是用於定義元件的行為和計算屬性。本文將介紹methods和computed屬性的使用方法和區別,並通過實際範例來幫助你理解。
Thumbnail
Vue 提供了兩種不同的 API 來建立和管理組件:Option API 和 Composition API。本文將介紹這兩種 API 的特點和差異,並透過實際範例來理解它們的使用方式。
Thumbnail
Vue 的單文件組件(Single File Components,SFC)是一種特殊的文件格式,讓我們可以將Vue 組件的模板、邏輯和樣式都寫在單一個文件當中。本文將介紹 Vue SFC,幫助開發者理解和使用 Vue SFC。
Thumbnail
Vue 是尤雨溪所開發的一個前端框架,Vue 提供了響應式數據綁定和組件化的開發模式,能方便開發者構建出具有良好交互性的前端應用。而 Vite 則是一個前端構建工具,用途是提供更快的開發體驗。然後,本文將介紹如何使用 Vite 建立一個 Vue 專案的開發環境,這是你學習 Vue 的第一步。
Thumbnail
如果前人已經走出一條最佳路徑,我們只顧著欣賞也會到山頂 關注點的改變 一個好的架構都會希望讓開發者能專注在”業務邏輯”的實現,可以提高專案的開發效率、減少開發者非關業務邏輯的事情而煩惱。例如: 開發者A: 請問元件的對話窗如何在確認時控制關閉或開啟狀態? 這個實際案例是架構師認為對話窗的動作
我在學習vue的過程中,一開始是先從輕前端(用CDN引入)開始學。這時候看Vue的官方文件會有些困惑,原因是有沒有用vite建構,在元件寫法上會有些差異。所以我寫下這篇筆記來整理這兩者寫法上的差異。 起手式 1.非建構:使用cdn 在html的header中插入以下script標籤 <s
父元件 傳遞方法使用@ <template>    ...    <Login @modalClose="modalClose"/> ... </template> <script setup>     const _modal = ref();     function m
父元件 傳遞變數時須加上冒號 子元件 接收props用法如下 本筆記參考: 1. https://www.netlify.com/blog/understanding-defineprops-and-defineemits-in-vue-3.2 2. https://juejin.cn/post/7
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
在 Vue 中,watch是用於進行數據監聽的,可以用來響應式的監聽資料的變化並執行相應的操作。本文介紹watch功能,並透過實際範例讓你更好的理解。
Thumbnail
在 Vue 中,methods和computed是用於定義元件的行為和計算屬性。本文將介紹methods和computed屬性的使用方法和區別,並通過實際範例來幫助你理解。
Thumbnail
Vue 提供了兩種不同的 API 來建立和管理組件:Option API 和 Composition API。本文將介紹這兩種 API 的特點和差異,並透過實際範例來理解它們的使用方式。
Thumbnail
Vue 的單文件組件(Single File Components,SFC)是一種特殊的文件格式,讓我們可以將Vue 組件的模板、邏輯和樣式都寫在單一個文件當中。本文將介紹 Vue SFC,幫助開發者理解和使用 Vue SFC。
Thumbnail
Vue 是尤雨溪所開發的一個前端框架,Vue 提供了響應式數據綁定和組件化的開發模式,能方便開發者構建出具有良好交互性的前端應用。而 Vite 則是一個前端構建工具,用途是提供更快的開發體驗。然後,本文將介紹如何使用 Vite 建立一個 Vue 專案的開發環境,這是你學習 Vue 的第一步。
Thumbnail
如果前人已經走出一條最佳路徑,我們只顧著欣賞也會到山頂 關注點的改變 一個好的架構都會希望讓開發者能專注在”業務邏輯”的實現,可以提高專案的開發效率、減少開發者非關業務邏輯的事情而煩惱。例如: 開發者A: 請問元件的對話窗如何在確認時控制關閉或開啟狀態? 這個實際案例是架構師認為對話窗的動作
我在學習vue的過程中,一開始是先從輕前端(用CDN引入)開始學。這時候看Vue的官方文件會有些困惑,原因是有沒有用vite建構,在元件寫法上會有些差異。所以我寫下這篇筆記來整理這兩者寫法上的差異。 起手式 1.非建構:使用cdn 在html的header中插入以下script標籤 <s
父元件 傳遞方法使用@ <template>    ...    <Login @modalClose="modalClose"/> ... </template> <script setup>     const _modal = ref();     function m
父元件 傳遞變數時須加上冒號 子元件 接收props用法如下 本筆記參考: 1. https://www.netlify.com/blog/understanding-defineprops-and-defineemits-in-vue-3.2 2. https://juejin.cn/post/7