nuxt3, vue3からpropsにジェネリクスを使えるようになりました。
今回はNuxt3で作成します。
例として以下のような type="text"
, type="number"
両方指定できるコンポーネントを作成します。
genericsなし
まずは、ジェネリクスなしで実装してみます。
この状態だと、emitされる値がnumberなのかstringなのか分かりません。
/components/atoms/Input.vue
<script lang="ts">
type Props = {
inputType?: 'number' | 'text';
value: number | string;
};
const props = withDefaults(defineProps<Props>(), { inputType: 'text' });
type Emits = {
// props.valueの型が分からない
(event: 'change', value: number | string): void;
};
const emits = defineEmits<Emits>();
const onChange = (event: any): void => {
emits('change', event.target.value);
};
</script>
<template>
<input :type="props.inputType" :value="props.value" @change="onChange" />
</template>
/pages/index.vue
<script setup lang="ts">
const strValue = ref('');
const numValue = ref(0);
</script>
<template>
<div>
<!--代入する際、型が分からないのでキャストしないといけない-->
<AtomsInput :value="strValue" @change="strValue = String($event)" />
<AtomsInput
input-type="number"
:value="numValue"
@change="numValue = Number($event)"
/>
</div>
</template>
genericsあり
scriptタグにgeneric="T extends number | string"
このように指定します。
すると親コンポーネントで指定された、valueの型がT
の型となります。
/components/atoms/Input.vue
<script setup lang="ts" generic="T extends number | string">
type Props = {
inputType?: 'number' | 'text';
value: T;
};
const props = withDefaults(defineProps<Props>(), { inputType: 'text' });
type Emits = {
// props.valueの型によってTが変わる
(event: 'change', value: T): void;
};
const emits = defineEmits<Emits>();
const onChange = (event: any): void => {
emits('change', event.target.value);
};
</script>
<template>
<input :type="props.inputType" :value="props.value" @change="onChange" />
</template>
/pages/index.vue
<script setup lang="ts">
const strValue = ref('');
const numValue = ref(0);
</script>
<template>
<div>
<AtomsInput :value="strValue" @change="strValue = $event" />
<AtomsInput
input-type="number"
:value="numValue"
@change="numValue = $event"
/>
</div>
</template>