現状
vueにはpropsで型の定義はできますが、細かく設定しようとすると一々オブジェクト形式で書かないといけなくなるし、ObjectやArrayだとvalidatorを自分で定義しないと全然チェックしてくれないので結構辛くなります。
仮に書けてもオブジェクトの中身がどんなものが入っているか分かりにくく、非常に使いづらいです。
export default {
props: {
data: {
type: Number,
required: true
},
arr: {
type: Array,
// 全て文字列か調べる
validator(arr) {
return arr.every((item) => typeof item === 'string'));
}
},
obj: {
type: Object,
validator(obj) {
return typeof obj.num === 'number' && typeof obj.text === 'string';
}
}
}
};
解決方法
今回はvue-typesというライブラリを使って型を定義したいと思います。これはReactのprop-typesを参考にして作られたものなので、Reactをやっていた方は馴染みやすいと思います。
https://www.npmjs.com/package/vue-types
サンプルコードも作ったのでこちらも参考にしてみてください。
警告が出るとうるさかったので正しいデータを入れて最初は何も出ないようにしています。
validationチェックを確認したい場合はApp.vueでComponentに渡している値を変えてみてください。
https://codesandbox.io/s/6zj47wkmpw
使い方
ざっと書くとこんな感じになります。後は親から渡されるプロパティがあっていなければ警告が出されます。
import VueTypes from 'vue-types';
export default {
props: {
// number型と定義
data: VueTypes.number,
// bool型で定義。必須にしたい場合は.isRequiredをつける
flag: VueTypes.bool.isRequired,
// arrayOfで配列の中身の型を定義できる
arr: VueTypes.arrayOf(VueTypes.string).isRequired,
// オブジェクトのkeyに指定はないが、valueの方はstring型にする
obj: VueTypes.objectOf(VueTypes.string).isRequired,
// オブジェクト型で、numとtextにそれぞれnumber型、string型と定義する
obj2: VueTypes.shape({
num: VueTypes.number.isRequired,
text: VueTypes.string.isRequired
}).isRequired,
// 配列の中身にオブジェクトの型を設定することもできる
arrObj: VueType.arrayOf(VueType.shape({
num: VueType.number.isRequired,
text: VueType.string.isRequired
})).isRequired
}
};
個人的には.isRequired
はデフォルトでついて欲しいですが、Reactのprop-typesもこの仕様なので仕方ないですね。
default値の設定
default値を指定した場合は.def(~)
を実行すればいいようです。
VueTypes.number.def(10);
VueTypes.object.def(() => ({ num: 10, text: 'text' }));
何も指定しなかった時はグローバルで定義した値をセットするようで、それが嫌な場合は上書きして使うようになります。僕はboolがtrueになっているのが嫌だったのでfalseに書き換えています。
デフォルトが何になるのかはドキュメントのほうを参照してください。
import VueTypes from 'vue-types';
// default値の設定を上書きする
VueTypes.sensibleDefaults.bool = false;
まとめ
vue-typesはまだそんなに人気がない感じですが、ドキュメントもしっかりしていますし、結構いいものだと思っています。少なくとも現状のVueの設定はかなりやりづらいものがあるので、型の設定をちゃんとするなら今回のようなライブラリを使うか、TypeScriptを使うかの検討をしたほうがいいと思いました。