Vue 泛型元件,讓 TypeScript 更精確

鱈魚-avatar-img
發佈於Vue
更新於 發佈於 閱讀時間約 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
留言分享你的想法!
avatar-img
鱈魚的魚缸
17會員
14內容數
各種鱈魚滾鍵盤的雜紀
鱈魚的魚缸的其他內容
2024/07/25
先前提到 Quasar 的 Dialog Plugin 很好用,再讓我補充一個用法。
Thumbnail
2024/07/25
先前提到 Quasar 的 Dialog Plugin 很好用,再讓我補充一個用法。
Thumbnail
2024/07/15
Quasar Dialog 的 Invoking custom component 很好用,但是有些困擾的地方,一起來看看有甚麼辦法吧。
Thumbnail
2024/07/15
Quasar Dialog 的 Invoking custom component 很好用,但是有些困擾的地方,一起來看看有甚麼辦法吧。
Thumbnail
2024/07/10
切換頁面卡卡有很多種原因,這裡舉的例子只針對元件太大的情境。 除了想辦法拆分外,還有一個方法就是利用 Vue 的 Async Component。
Thumbnail
2024/07/10
切換頁面卡卡有很多種原因,這裡舉的例子只針對元件太大的情境。 除了想辦法拆分外,還有一個方法就是利用 Vue 的 Async Component。
Thumbnail
看更多
你可能也想看
Thumbnail
各位使用 Vue.js 開發的小夥伴們,你們都怎麼實作父子層組件資料的雙向綁定呢?如果你還在寫 prop + emit 的話,不妨進來看看吧。
Thumbnail
各位使用 Vue.js 開發的小夥伴們,你們都怎麼實作父子層組件資料的雙向綁定呢?如果你還在寫 prop + emit 的話,不妨進來看看吧。
Thumbnail
本章節旨在介紹 TypeScript 的基本資料型別,包括內建型別、型別轉換、自訂型別、元組、集合、陣列、和字典型別。透過理解和使用這些型別,可以提高代碼的可讀性和可維護性。
Thumbnail
本章節旨在介紹 TypeScript 的基本資料型別,包括內建型別、型別轉換、自訂型別、元組、集合、陣列、和字典型別。透過理解和使用這些型別,可以提高代碼的可讀性和可維護性。
Thumbnail
在 Vue 專案中使用 Apollo Graphql Client 從 API 獲取資料,由於資料結構較為複雜,筆者便跟著網路教學使用 codegen 工具自動化產生 TypeScript 型別定義。在某個元件中,需要使用 defineProps 來撰寫型別定義,結果⋯⋯
Thumbnail
在 Vue 專案中使用 Apollo Graphql Client 從 API 獲取資料,由於資料結構較為複雜,筆者便跟著網路教學使用 codegen 工具自動化產生 TypeScript 型別定義。在某個元件中,需要使用 defineProps 來撰寫型別定義,結果⋯⋯
Thumbnail
大家好,我是鱈魚。(^∀^●)ノシ Vue 3.3 終於新增了泛型元件(Generic Component),這讓我們可以在 TypeScript 環境中得到更準確的型別提示。( •̀ ω •́ )✧ 讓我們一起來看看吧!
Thumbnail
大家好,我是鱈魚。(^∀^●)ノシ Vue 3.3 終於新增了泛型元件(Generic Component),這讓我們可以在 TypeScript 環境中得到更準確的型別提示。( •̀ ω •́ )✧ 讓我們一起來看看吧!
Thumbnail
上一篇文章分享了 TypeScript 的定義、前端角色定位,如果你不是很確定「TypeScript 是什麼?」、「TypeScript 作為 JavaScript 的超集,在網頁開發扮演怎麼樣的角色?」這兩個問題的答案,建議可以回到上一篇先了解一下。
Thumbnail
上一篇文章分享了 TypeScript 的定義、前端角色定位,如果你不是很確定「TypeScript 是什麼?」、「TypeScript 作為 JavaScript 的超集,在網頁開發扮演怎麼樣的角色?」這兩個問題的答案,建議可以回到上一篇先了解一下。
Thumbnail
Vue3 筆記,指令進階篇
Thumbnail
Vue3 筆記,指令進階篇
Thumbnail
Vue3 學習筆記,專案建立與基礎響應式篇
Thumbnail
Vue3 學習筆記,專案建立與基礎響應式篇
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News