ジェネリクスをなんとなく使っていて、理解が曖昧なままだったので、簡単な例を用いて説明とoutputを含めて記事にしてみました。
参考記事
目次
ジェネリクスとは
仮の型を作っておいて、実際に使うときに型を指定する方法
一般的な関数
//const 変数 =(引数変数:型)戻り値の型 =>{}
const funcTest = (suzi:number) number => {
return suzi
}
引数・戻りにあらかじめ方を付けておきます。
もしnumber型意外を使ったときにエラーが起きます
const testReturn = funcTest(123); //これはエラーなし
const testReturn = funcTest('ああ'); //これはエラー
ジェネリクスを使った関数
//const 変数 =<ジェネリクス型>(引数変数:型)戻り値の型 =>{}
const funcTest = <T> (arg:T) T => {
return arg
}
引数・戻り値も曖昧な状態で「T」という状態で定義しておきます。
こうすることで下の例でいうと実際に使用するときに、同じ関数でも使用するときに数字型か文字型で使うことができます。
実際に使うときに型を確定させることができます。
const testReturn = funcTest<number>(123); //エラーなし
const testReturn = funcTest<string>('ああ'); //エラーなし
実際にはオブジェクト型で使うこともでき、同じ関数でオリジナルの型を使うことができます。
type reshipi = {
name:string
size:number
howTo:string
}
const tamagoCook:reshipi = {
name : 'たまごやき'
size : 1
howTo : '3分焼く'
}
const testReturn = funcTest<reshipi>(tamagoCook); //エラーなし
なぜvueでジェネリクスを使うことが多いの?
下記のような理由があるためです。
- コンポーネントを再利用するため
- 明示的にすることでバグを減らすため
型を保持しつつコンポーネントを再利用するため
例えばH2表示フォームのコンポーネントを作ったとします。
データは文字型と数字型にしています。
<template>
<div class="border">
<h2>{{data}}</h2>
</div>
</template>
<script setup lang="ts">
const props =defineProps<{
input : string|number
}>(
</script>
こうすることで下記のように、文字型の場合と数字型の場合の2種類の型に柔軟に対応し、用途によって再利用することができます。
<template>
<div>
<MyComponent data="Hello, Vue.js!" />
<MyComponent data="42" />
</div>
</template>
<script setup lang="ts">
</script>
明示的にすることでバグを減らすため
例えば、下記のような親コンポーネントで入力して、子コンポーネントで入力した値を表示するコンポーネントとつくったとします。
<template>
<p>たまご料理名:{{reshipi.name}}</p>
<p>たまご個数:{{reshipi.size}}</p>
<p>たまご調理法:{{reshipi.howTo}}</p>
</template>
<script>
type reshipi = {
name:string
size:number
howTo:string
}
const props = defineProps<{
tamagoCook:reshipi
}>()
</script>
<template>
<div>
<!-- 親コンポーネントでname, size, howToを入力するフォーム -->
<label>たまご料理名: <input v-model="recipeName" /></label>
<label>たまご個数: <input v-model.number="recipeSize" type="number" /></label>
<label>たまご調理法: <input v-model="recipeHowTo" /></label>
<!-- 子コンポーネントにpropsとして渡す -->
<ChildComponent :tamagoCook="{ name: recipeName, size: recipeSize, howTo: recipeHowTo }" />
</div>
</template>
<script setup lang="ts">
// 親コンポーネントのデータ
const recipeName = ref('');
const recipeSize = ref(0);
const recipeHowTo = ref('');
export default {
components: { ChildComponent },
};
</script>
rechipeSizeの部分に文字列をいれたり、rechipeNameの部分に数値を入れたりすると、子コンポーネントで定めている型と異なるのでエラーになります。
ですが、下記のようにrefの前にジェネリクスを明示的に置くことで子要素に渡す前に型を判定でき、エラーを防ぐことができます。
<script setup lang="ts">
// 親コンポーネントのデータ
const recipeName = ref<string>('');
const recipeSize = ref<number>(0);
const recipeHowTo = ref<string>('');
export default {
components: { ChildComponent },
};
</script>
使用するときにジェネリクスを使うことで、コンパイル時に型エラーを見つけることができます。
コメント