LoginSignup
2
1

More than 3 years have passed since last update.

Vue.js で JSDoc により $refs の中身を確認して実装する

Last updated at Posted at 2019-09-28

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 の記述にしてみる

やってみます。

親コンポーネントで子コンポーネント使用

child.vue
<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 メソッドを親コンポーネント側で使用する形です。

parent.vue
<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.vuecomponents に指定し ref="child" を設定、
mounted() にて子コンポーネントのメソッド checkName() を使用しています。

no-jsdoc.jpg

any です。
いつもの光景ですね。

親コンポーネントに JSDoc 記述 (Vue.extend 使用)

ここで子コンポーネントの記述のように親コンポーネントにも JSDoc の記述を追加します。

jsdoc-parent.vue
<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 での記述と同様、
InstanceTypetypeof Child を指定しています。

これを確認してみると・・・

jsdoc-parent.jpg

子コンポーネントで JSDoc で記述した内容が親コンポーネントでも確認することができました。

親コンポーネントに JSDoc 記述 (Vue.extend 不使用)

以下は Vue.extend を使用しない形式です。

Vue をファイル内で @typedefRefs との Intersection Type とし、
data に JSDoc で型指定を行うことでコンポーネントオプション内の VueRefs を含んだものにしております。

Data@typedef では @property が存在しない定義だと、
$refs 配下がまるごと any になったのでダミーのプロパティなどを定義しないとだめなようです。

export-default
<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>
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1