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
孩子寫功課時瞇眼?小心近視!這款喜光全光譜TIONE⁺光健康智慧檯燈,獲眼科院長推薦,網路好評不斷!全光譜LED、180cm大照明範圍、5段亮度及色溫調整、350度萬向旋轉,讓孩子學習更舒適、保護眼睛!
Thumbnail
孩子寫功課時瞇眼?小心近視!這款喜光全光譜TIONE⁺光健康智慧檯燈,獲眼科院長推薦,網路好評不斷!全光譜LED、180cm大照明範圍、5段亮度及色溫調整、350度萬向旋轉,讓孩子學習更舒適、保護眼睛!
Thumbnail
創作者營運專員/經理(Operations Specialist/Manager)將負責對平台成長及收入至關重要的 Partnership 夥伴創作者開發及營運。你將發揮對知識與內容變現、影響力變現的精準判斷力,找到你心中的潛力新星或有聲量的中大型創作者加入 vocus。
Thumbnail
創作者營運專員/經理(Operations Specialist/Manager)將負責對平台成長及收入至關重要的 Partnership 夥伴創作者開發及營運。你將發揮對知識與內容變現、影響力變現的精準判斷力,找到你心中的潛力新星或有聲量的中大型創作者加入 vocus。
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 的超集,在網頁開發扮演怎麼樣的角色?」這兩個問題的答案,建議可以回到上一篇先了解一下。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News