RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

【2021年版】Vue.js + TypeScriptの開発スタイル

はじめに

こんにちは。フロントエンドチームのayoshです。
この記事では、TypeScriptとVue.jsで開発を行う方法について紹介していきたいと思います。

自分の参加しているプロダクトでもTypeScriptとVue.jsを用いた開発をしていますが、最近のWebアプリケーションのフロントエンド開発ではTypeScriptとReact、もしくはTypeScriptとVue.jsで開発をしている現場は多いのではないでしょうか?

主に2通りのやり方がある

様々な記事でも紹介されていますが、Vue.jsとTypeScriptで開発をする方法は多く分けると2つあると言われています(今回は触れませんが、composition APIも含めて3通りある、という見方もあるようです)。

  • Vue.extend()を用いた書き方(いわゆる Object Style
  • class MyComponent extends Vueとする書き方(いわゆる Class Style

書き方にかなりの違いがありそれぞれ特徴があるので、比較をされている記事も結構ありますが、ここ数年で状況が結構流動的だったようなので改めてまとめてみたいと思います。

想定している読者

読み手として下記のような方を想定しています。

  • Vue.js + JavaScriptで開発をしたことがある
  • TypeScriptはなんとなくわかるが、Vue.jsのプロジェクトに導入したことはない

要するに、

  • Vue + JS = 🙆‍♂️
  • Vue + TS = これから

という方( = ちょっと前の自分)です。

ではまずClass Styleから紹介します。

Class Styleの書き方

こちらは名前の通り、コンポーネントをクラスとして宣言します。
Vue.js公式よってメンテナンスされているvue-class-componentに加え、デコレータによってより見易く書けるvue-property-decoratorを使用する書き方で、Vue CLIを用いてvue createvue add typescriptした際、Use class-style component syntax?の質問にyesとした場合に構成されるのがこのスタイルです。

import { Component, Prop, Vue } from "vue-property-decorator";

interface ComplexMessage {
  title: string,
  okMessage: string,
  cancelMessage: string
}

@Component({
  // conponentsは@Componentデコレータの引数に渡す
  components: {
    MyComponent,
  },
})
export default class HelloWorld extends Vue {
  // propsはそれぞれ@Propデコレータを使って定義する
  @Prop() public message: string;
  @Prop({ required: true }) public complexMessage!: ComplexMessage;

  // dataはクラスのプロパティとして定義する
  private name: string = 'Example Name';
  private count: number = 0;

  // computedはクラスのgetterメソッドとして実装する
  get isZero(): boolean {
    return this.count === 0;
  }

  // methodsはクラスのメソッドとして実装する
  public outputMessage(): string {
    return this.message;
  }

  // watchは@Watchデコレータの引数にwatchする対象を渡す
  @Watch('count')
  public doSomething(c: number) {
    // ...do something
  }
}

Class Styleの特徴

それぞれのOptionをオブジェクトでまとめて記述する基本のVue.jsの書き方と違って、クラス構文を用いて記述する為、少しスッキリして見えます。よりTypeScriptっぽい書き方という表現もできそうです。
ただ、JavaScript + Vue.jsでの書き方に慣れている方であれば、書き方が大きく変わる事で少し困惑することもあるかもしれません。

その他にも以下のような特徴があげられるようです。

利用者が多く資料が豊富、というのは結構惹かれるポイントです。

では続いてObject Styleを見てみましょう。

Object Styleの書き方

Vue.js公式のTypeScriptのサポートのページでも主に紹介されているのがこのスタイルです。Vue.js + JavaScriptで開発をしたことがある方は見慣れた形ではないでしょうか。 Vue CLIを用いてvue createvue add typescriptした際、Use class-style component syntax?の質問にnoとした場合はこのように記述されています。

import Vue from "vue";

// dataオブジェクトのそれぞれのプロパティの型をまとめて定義し、dataの返り値の型として注釈する
export type DataType = {
  name: string;
  count: number;
}

// Object型のpropの型を定義、PropType<>に型引数として渡す
interface ComplexMessage {
  title: string,
  okMessage: string,
  cancelMessage: string
}

export default Vue.extend({
  name: "HelloWorld",
  components: {
    // JavaScript + Vue.js同様の記述
    MyComponent,
  },
  props: {
    // プリミティブな型は普通に型注釈する
    message: String,
    // Objectなどの場合はPropType<>の型引数に定義した型を渡してキャストする
    complexMessage: {
      type: Object as PropType<ComplexMessage>,
      required: true
    }
  },
  data(): DataType {
    // dataオブジェクトの返り値を型注釈
    return {
      name: 'Example Name',
      count: 0,
    }
  },
  methods: {
    // それぞれの返り値を型注釈する
    outputMessage(): string {
      return this.message;
    }
  },
  computed: {
    // それぞれの返り値を型注釈する
    isZero(): boolean {
      return this.count === 0;
    }
  },
  watch: {
    // 引数・返り値に型注釈する
    count(c: number): void {
      // ...do something
    }
  }
});

Object Styleの特徴

こちらはimport Vue from "vue";としている事からわかるように、本体に追加されている機能です。
大枠はほとんどJavaScriptの書き方と変わらず、TypeScriptの基本的な型注釈ができればJavaScriptからの移行も容易にできそうです。
一方、それぞれのOptionはオブジェクトとして区切られる為、懸念ごとが区切られてしまうという弱点はJavaScriptでの書き方でのデメリットをそのまま受け継いでいるともいえます。

どっちで書く?

簡単に両方の特徴をまとめてみましたが、どちらで書くのが良いのでしょうか。

見やすさ・馴染みやすさ

これは好みが分かれるところかもしれません。TypeScriptでクラスを積極的に使った書き方に慣れていればClass Styleの書き方はスッキリとしていて見やすいと感じるでしょうし、JavaScriptでVue.jsを書いていた人からするとObject Styleの書き方は馴染みがあって移行もスムーズでしょう。

利用者の多さ

これはClass Styleに軍配が上がっているようです。Vue.jsの初期からあることに加え、v2.5以前のObject StyleではthisPropsの型注釈・型推論に難があったこともあり、Class Styleで開発をする人の方が多い様子。利用者が多ければ記事などで情報も見つかり易いといったメリットもあります。

公式のサポート

長く運用するプロジェクトであれば公式のサポートもきになるところです。
利用者の多さで優っていたClass Styleですが、Vue3ではRFCで廃案(Abandoned)となっています(サポートは続けられるとの事)。対してObject StyleはVue本体の機能なので、この面ではメリットになりそうです。

まとめ

Object Styleにあったthispropsの型の問題もあり、一昔前まではClass Style一択の風潮が見られたものの、v2.5でこれらが改善されてからはObject Styleを推す記事もよく見つかります。また、今回は触れなかったVue3系のcomposition APIを使うとObject Styleにある「関心ごとの分離」などの弱点を補える事もあり、情勢の逆転もあり得るかもしれません。

実際にはVue3系の導入や周辺ライブラリなど考慮すべき点はまだまだありますが、この記事では簡単にですがClass StyleとObject Styleの特徴をまとめてきました。
これからVueプロジェクトにTypeScriptを導入しようとしている方の助けになれば幸いです。

参考


◆TECH PLAY
techplay.jp

◆connpass
rakus.connpass.com

Copyright © RAKUS Co., Ltd. All rights reserved.