Help us understand the problem. What is going on with this article?

[Vue+TypeScript] Vue.extend で Vue らしさを保ちつつ TypeScript で書くときの型宣言についてまとめた

はじめに

Vue + TypeScript の組み合わせでVueを書くときに、vue-property-decorator を利用して書いていくことが多いと思います。
ただ vue-property-decorator を利用すると、どうしてもVueらしさがなくなるというか、よりTypeScriptにらしい書き方になると感じています。
せっかくJavaScriptでVue書けるようになったのに、全然書き方が違うじゃないか…と挫折しかけることもあるんじゃないでしょうか?
ちなみに私は vue-property-decorator で書くほうが慣れているので好きですが、Vue入門者には厳しいところがあると思うので、 Vue.extend ベースでTypeScriptを書いていくという方法を紹介するのと、その際の型宣言についてもまとめていこうと思います。

VueをTypeScriptで書きたいけど、 vue-property-decorator は使いたくない…って人の参考になればいいなーと思います。

Vue.extend ??

TypeScript内でVueモジュールをimport/extendして書く方法です。
JavaScriptでのVueコンポーネントの記述に近い書き方でTypeScriptを書くことができます。

<script lang="ts">
  import Vue from "vue"

  export default Vue.extend({
    name: "component",
    data() {
      return {
        value: "hoge"
      }
    }
  })
</script>

環境構築

VueCLIで簡単に構築することができます。
TypeScriptを選択して、class-styleコンポーネントシンタックスを利用しないと選択すればいいです。

? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
 ◯ Babel
❯◉ TypeScript
 ◯ Progressive Web App (PWA) Support
 ◯ Router
 ◯ Vuex
 ◯ CSS Pre-processors
 ◯ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing
? Use class-style component syntax? (Y/n) n

これで Vue.extend の環境が構築されます。簡単ですね。

Vue.extend における型

Vue.extend ベースでTypeScriptで書いていく際の型宣言を紹介していこうと思います。

props

Propについてはネイティブコンストラクターを付与することで、内部で型推論されます。
またArrayやObjectの詳細な型宣言については PropType を利用することで宣言することができます。

<script lang="ts">
  import Vue, { PropType } from "vue"

  export type PropObjType = {
    id: string
    index: number
  }

  export default Vue.extend({
    props: {
      val: {
        type: String,
        default: ""
      },
      obj: {
        type: Object as PropType<PropObjType>,
        default: () => ({
          id: "",
          index: 0
        })
      }
    }
  })
</script>

ここで注意が必要なのが、ビルド時のコンパイルエラーを得ることができないという点です。ただ実行時のエラーを得ることはできます。
また用意されているネイティブコンストラクターは以下の通りです。

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

data

data()関数に向けて型を定義し、型アノテーションを付与します。

<script lang="ts">
  import Vue from "vue"

  export type DataType = {
    value: string
    enable: boolean
    count: number
  }

  export default Vue.extend({
    data(): DataType {
      return {
        value: "hoge",
        enable: true,
        count: 0
      }
    }
  })
</script>

lifecycle hooks

lifecycle hooksで着火するイベントは基本的に void 型の関数

<script lang="ts">
  import Vue from "vue"

  export default Vue.extend({
    created(): void {
      console.log("Created!!!")
    }
  })
</script>

computed

computedで呼び出される関数が返す値に対する型を宣言する

<script lang="ts">
  import Vue from "vue"

  export type DataType = {
    value: string
    enable: boolean
    count: number
  }

  export default Vue.extend({
    data(): DataType {
      return {
        value: "hoge",
        enable: true,
        count: 0
      }
    },

    computed: {
      isEnabled(): boolean {
        return this.enable
      },
      getCount(): number {
        return this.count
      }
    },
  })
</script>

methods

methodsで呼び出される関数が返す値に対する型を宣言する

<script lang="ts">
  import Vue from "vue"

  export type DataType = {
    value: string
    enable: boolean
    count: number
  }

  export default Vue.extend({
    data(): DataType {
      return {
        value: "hoge",
        enable: true,
        count: 0
      }
    },

    methods: {
      countUp(): void {
        this.count += 1
      },
      getValue(): string {
        return this.value
      }
    }
  })
</script>

まとめ

  • Vueらしさを保ちつつTypeScriptで書きたいって人 → Vue.extend
  • VueらしさよりTypeScriptらしく書きたいって人 → vue-property-decorator

という感じかなって思います。自分に合った方法でより楽しくVueを書いていきましょう!
ではまた!!!

is_ryo
(IoTチョットワカル)フロントエンドエンジニア。 Vue.js / AWS / GraphQL / Serverless
https://is-ryo.com
acall
ACALLは、「Life in Work and Work in Life for Happiness」をVISIONとして、どこでも安心・安全・快適なワークスタイルを実現するワークスペース管理プラットフォーム「WorkstyleOS」を開発・提供しています。オフィスワークとリモートワークのベストミックスを通じて、人々の「くらし」と「はたらく」を自由にデザインできる世界を目指します。
https://www.workstyleos.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away