Vue.js で JSDoc により $refs の中身を確認して実装する
親コンポーネントが子コンポーネントに ref
ディレクティブを指定し、
そのメソッドなどを使用したりしますが中身を想像しながら対応することはおおくあります。
そこで JSDoc との連携により子コンポーネントのもっているモノを確認しようと試みます。
VeeValidate のドキュメントの記述より
最近 3.0 のリリースされた VeeValidate のドキュメントを読んでいたところ
以下のような記述を目にしました。
Adding Errors Manually - VeeValidate
Typescript and $refs
If you are using TypeScript you may face issues with $refs not giving you the correct > > typings, you can solve that by defining them as ValidationProvider instances:
export default class App extends Vue {
$refs!: {
provider: InstanceType<typeof ValidationProvider>;
};
}
これは TypeScript での VeeValidate の Validation Provider
を使用する際の記述例です。
ref="provider"
を指定したものを親コンポーネント側でメソッドを利用する際に型を明示しています。
VeeValidate での事例を JSDoc の記述にしてみる
やってみます。
親コンポーネントで子コンポーネント使用
<template>
<div>child</div>
</template>
<script>
import Vue from 'vue'
/**
* @typedef {Object} Methods
* @property {{(): boolean}} checkName なまえをちぇっくするめそっど
*/
// eslint-disable-next-line
/** @typedef {import("vue/types/options").ThisTypedComponentOptionsWithRecordProps<Vue, {}, Methods, {}, {}>} Options */
/** @type {Options} */
export const options = {
methods: {
checkName() {
return true
},
},
}
export default Vue.extend(options)
</script>
子コンポーネントとして child.vue
を用意しましたが
checkName
メソッドを親コンポーネント側で使用する形です。
<template>
<div>
parent
<child ref="child" />
</div>
</template>
<script>
import Vue from 'vue';
import Child from './child.vue';
export const options = {
components: {
Child,
},
mounted() {
console.log(this.$refs.child.checkName());
},
};
export default Vue.extend(options);
</script>
親コンポーネント側で child.vue
を components
に指定し ref="child"
を設定、
mounted()
にて子コンポーネントのメソッド checkName()
を使用しています。
any
です。
いつもの光景ですね。
親コンポーネントに JSDoc 記述 (Vue.extend 使用)
ここで子コンポーネントの記述のように親コンポーネントにも JSDoc の記述を追加します。
<template>
<div>
parent
<child ref="child" />
</div>
</template>
<script>
import Vue from 'vue'
import Child from './child.vue'
/**
* @typedef {Object} Refs
* @property {InstanceType<typeof Child>} child
*/
/**
* @typedef {Object} Data
*/
// eslint-disable-next-line
/** @typedef {import("vue/types/options").ThisTypedComponentOptionsWithRecordProps<Vue & { $refs: Refs }, Data, {}, {}, {}>} Options */
/** @type {Options} */
export const options = {
components: {
Child,
},
mounted() {
console.log(this.$refs.child.checkName())
},
}
export default Vue.extend(options)
</script>
記述としては子コンポーネントと同様の構成ですが
ポイントは @typedef
にて Refs
を定義し、ThisTypedComponentOptionsWithRecordProps
の使用箇所にて Vue
に対し { $refs: Refs }
を混ぜ込んでいる点です。
Refs["child"]
には VeeValidate での記述と同様、
InstanceType
に typeof Child
を指定しています。
これを確認してみると・・・
子コンポーネントで JSDoc で記述した内容が親コンポーネントでも確認することができました。
親コンポーネントに JSDoc 記述 (Vue.extend 不使用)
以下は Vue.extend
を使用しない形式です。
Vue
をファイル内で @typedef
で Refs
との Intersection Type とし、
data
に JSDoc で型指定を行うことでコンポーネントオプション内の Vue
を Refs
を含んだものにしております。
Data
の @typedef
では @property
が存在しない定義だと、
$refs
配下がまるごと any
になったのでダミーのプロパティなどを定義しないとだめなようです。
<template>
<div>
parent
<Child ref="child" />
</div>
</template>
<script>
import Child from './child.vue'
/**
* @typedef {Object} Refs
* @property {InstanceType<typeof Child>} child
*/
/**
* @typedef {import('vue').default & { $refs: Refs }} Vue
*/
/**
* @typedef {Object} Props
*/
/**
* @typedef {Object} Data
* @property {string} id
*/
export default {
components: {
Child,
},
/** @typedef {import("vue/types/options").DataDef<Data, Props, Vue>} DataDef */
/**
* @type {DataDef}
* @return {Data}
*/
data() {
return {
id: '',
}
},
mounted() {
console.log(this.$refs.child.checkName())
},
}
</script>