完成イメージ
コンポーネント
RadioButton.vue
<template>
<div class="border rounded border-success-subtle">
<div v-for="item in items" :key="item.id">
<input
type="radio"
:id="item.id"
:name="props.name"
:value="item.value"
v-model="modelValue"
:required="props.required"
/>
<label :for="item.id">{{ item.labelName }}</label>
</div>
</div>
</template>
<script setup lang="ts" generic="T extends string | boolean | undefined">
export interface InputRadioItem<T> {
id: string;
labelName: string;
value: T;
}
const props = defineProps<{
modelValue: T;
name: string;
items: InputRadioItem<T>[];
required?: boolean;
}>();
interface Emits {
(e: "update:modelValue", value: T): void;
}
const emits = defineEmits<Emits>();
const modelValue = computed({
get: () => props.modelValue,
set: (value) => {
emits("update:modelValue", value);
},
});
</script>
- generic="T"を定義する
- 許容したい型をextendsに定義する
使用側
index.vue
<template>
<form>
<RadioButton :items="listItems" v-model="selectedValue" name="fruitsRadio" />
selected: {{ selectedValue }}
</form>
</template>
<script setup lang="ts">
import type { InputRadioItem } from "~/components/RadioButton.vue";
const radioItems: InputRadioItem<string>[] = [
{ id: "apple", labelName: "りんご", value: "apple" },
{ id: "banana", labelName: "バナナ", value: "banana" },
{ id: "oranage", labelName: "みかん", value: "oranage" },
];
const selectedValue = ref(undefined);
</script>
- InputRadioItemでvalueに使用したい型を指定することで、modelValueの型と連動する
- valueとselectedValueが異なるとコンパイルエラーが出る