Vue 泛型元件,讓 TypeScript 更精確
大家好,我是鱈魚。(^∀^●)ノシ
Vue 3.3 終於新增了泛型元件(Generic Component),可以在 TypeScript 環境中得到更準確的型別提示了!ˋ( ° ▽、° )
這個泛型元件與 TypeScript 的 Generic 是同一個概念,不知道 Generic 的朋友可以先來來複習一下。
甚麼?你說你沒有使用 TypeScript?抱歉浪費您 5 秒鐘,可以上一頁了。(>人<;)
或者在離開前路過文件湊個熱鬧。( •̀ ω •́ )y
有使用 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 的朋友們別擔心,讓我們複習一下。
TIP
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 selectedAnyDatum = ref<User>()
</script>
<template>
<!-- anyDatum 與 option 型別不同 -->
<select-any v-model="anyDatum" :options="options" :option-label="getLabel" />
<!-- modelValue 沒有給矩陣 -->
<select-any v-model="selectedAnyDatum" 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 selectedGenericDatum = ref<User>()
const selectedGenericData = ref<User[]>([])
</script>
<template>
<!-- Type '{ age: number; }' is not assignable to type 'User | User[]'.ts(2322) -->
<select-generic v-model="anyDatum" :options="options" :option-label="getLabel" />
<!-- Type 'User' is not assignable to type 'User[]'.ts(2322) -->
<select-generic v-model="selectedGenericDatum" multiple :options="options" :option-label="getLabel" />
<!-- 正確 -->
<select-generic v-model="selectedGenericData" multiple :options="options" :option-label="getLabel" />
</template>
TypeScript 成功重返光榮。o((>ω< ))o
文章到此結束了,感謝您的閱讀,以上程式碼可以在此取得。
有其他想法請不吝告訴我,鱈魚感謝您!(o゜▽゜)o☆
總結 🐟
- Vue 3.3 新增泛型元件
- 泛型元件可以讓 TypeScript 推導更精確