Works by

Ren's blog

@rennnosuke_rk 技術ブログです

【Vue.js】Vue + TypeScript + vue-property-decoratorでのクラスメンバの可視性はどうするべきか?

f:id:rennnosukesann:20181217223208p:plain:w300

Vue + Typescript + vue-property-decoratorでコンポーネントをクラス宣言的に記述する際、data はクラスのインスタンス変数として定義し、
method はクラスのメソッドとして記述できます。

<template>
    <p v-for="(b, i) in books" :key="i">{{b.name}}</p>
</template>

<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator';
import { BookFactory } from '@/service/factory/book';

@Component
export default class BookNames extends Vue {
    books: Book[] = [];

    fetchBooks(){
        books = BookFactory.findBooks();
    }
}
</script>

このとき、これらクラスメンバのアクセス修飾子はどのようにすればよいのか気になりました。

通常のTypeScriptクラス同様、コンポーネントクラスではアクセス修飾子を設定できます。

    private books: Book[] = [];

    private fetchBooks(){
        books = BookFactory.findBooks();
    }

この修飾子をprivateにしようがpublicにしようが、テンプレートからは参照できます。

<template>
    <p v-for="(b, i) in books" :key="i">{{b.name}}</p>
</template>

では、ref` を使用した外部コンポーネントからの呼び出しではどうなるのでしょうか。

<template>
    <book-names ref="books"/>
</template>

<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator';
import { BookNames } from '@/components/molecules/BookNames';

@Component({
    components:{
        BookNames
    }
})
export default class Parent extends Vue {
    mounted(){
        console.log(this.$ref.books.books); // [ {name: "hoge"}, ... ]
    }
}
</script>

privateでも呼べてしまいます。外部コンポーネントからの呼び出しでも可視性は無視されました。*1

結局、TSをJSにトランスパイルする際にはTSの可視性は無視される(トランスパイルの際の構文チェックでのみ可視性が有効である)ため、
TS(Vue)の静的構文チェックで引っかからない限りアクセス修飾子は意味を成しません。

ex. privateメンバを持つTypeScriptクラスのトランスパイル

export default class Child {
    private hoge: string = "hoge";
}

"use strict";
exports.__esModule = true;
var Child = /** @class */ (function () {
    function Child() {
        this.hoge = "hoge";
    }
    return Child;
}());
exports["default"] = Child;

ただし、$refs の持つメンバへの型定義を無理やり行えば、クラスの可視性は有効になります。

export interface Context {
    readonly refs: {
        [key: string]: BookName;
    };
}

ただし、これでは $refsBookName しか参照できなくなります。


特に意味を成さないのであれば、privateはクラス内参照、修飾子なし/publicであれば外部参照用のメソッドなど、あくまで読み手に対するマーカとして使用していくのがベターなんですかね。。。

*1:本当は、親から子の場合でもコンポーネントへのメンバに直接アクセスすべきではありません。