LoginSignup
676
604

More than 3 years have passed since last update.

Vue.js to TypeScriptの書き方一覧

Last updated at Posted at 2019-04-13

最近ひたすら既存のVueプロジェクトのTypeScript化をやっているのでメモとしてまとめます。

(2019/09/09 追記)
vue-class-componentはvue3のRFCから外されたようで、現在は、Composition APIがRFCとなっています。
Composition APIでのTypeScript化についてはこちらの記事をどうぞ
https://qiita.com/ryo2132/items/f055679e9974dbc3f977

前提

  • .vueファイルで<script lang="ts">を使う
  • vue-property-decoratorを使ったデコレータ方式のTypeScript化を行う

data

dataはそのままクラスのプロパティとして宣言します。

JavaScript

<script >
export default {
  name: 'Human',
  data() {
    return {
      name: '山田 太郎',
      age: 19
    };
  }
};
</script>

TypeScript

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';

@Component
export default class Human extends Vue {
  name: string = '山田 太郎';
  age: number = 19;
}
</script>

components

SFCで他Vueコンポーネントを参照する際に使うComponentsは
@Component()デコレータにcomponentsをkeyに持つオブジェクトを渡し定義します.

JavaScript

<script>
import Header from './Header'
import Footer from './Footer'

export default {
  name: 'Page',
  components: {
    Header,
    Footer
  }
}
</script>

TypeScript

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import Header from './Header.vue';
import Footer from './Footer.vue';

@Component({
  components: {
    Header,
    Footer
  }
})
export default class Page extends Vue {
}
</script>

directive

v-hogeのような独自のdirectiveを追加する場合はそのまま@components()にオブジェクトを渡す

JavaScript

<script>
import HogeDirective from './HogeDirective'

export default {
  name: 'Page',
  directives: {
    hoge: HogeDirective
  }
}
</script>

TypeScript

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import HogeDirective from './HogeDirective'

@Component({
  directives: {
    hoge: HogeDirective
  }
})
export default class Page extends Vue {
}
</script>

props

親コンポーネントからデータを受け取るpropsは@Propデコレータを使い定義します。

@Prop(options: (PropOptions | Constructor[] | Constructor) = {})

JavaScript

<script>
export default {
  name: 'Post',
  props: {
    contents: { default: '', type: String, require: true },
    postNumber: { default: 0, type: [Number, String], require: true },
    publish: { default: true, type: Boolean, require: true },
    option: { type: Object, require: false } // optionには {new: boolean, important: boolean, sortNumber: number} が設定される想定
  }
}
</script>

TypeScript

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

@Component
export default class Post extends Vue {
  @Prop({ default: '' })
  contents!: string;

  @Prop({ default: 0 })
  postNumber!: number | string;

  @Prop({ default: false })
  publish!: boolean;

  @Prop
  option?: {
    new: boolean,
    important: boolean,
    sortNumber: number
  };
}
</script>

computed

算出プロパティはgetter付きのメソッドで定義します。

JavaScript

<script>
export default {
  name: 'Human',
  data () {
    return {
      firstName: '太郎',
      lastName: '山田'
    }
  },
  computed: {
    fullName () {
      return `${this.firstName} ${this.lastName}`
    }
  }
}
</script>

TypeScript

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';

@Component
export default class Human extends Vue {
  firstName: string = '太郎';
  lastName: string = '山田';

  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }

}
</script>

emit

親コンポーネントに値を送信する$emitは@Emitデコレータを使いfunctionとして定義します。
メソッド名が、$emitに渡すイベント名がメソッド名と同様の場合は、@Emit()の引数(イベント名)は省略できます。
※ 以下のcountUpのケース。camelCaseとkebabe-caseは自動で変換されます

@Prop(options: (PropOptions | Constructor[] | Constructor) = {})

JavaScript

<script>
export default {
  name: 'Counter',
  data () {
    return {
      count: 0
    }
  },
  methods: {
    countUp (n) {
      this.count += n
      this.$emit('count-up', n)
    },
    resetCount () {
      this.count = 0
      this.$emit('reset')
    }
  }
}
</script>

TypeScript

<script lang="ts">
import { Component, Emit, Vue } from 'vue-property-decorator';

@Component
export default class Counter extends Vue {
  count: number = 0;

  @Emit('count-up')
  countUp(n) {
    this.count += n;
    return n;
  }

  @Emit('reset')
  resetCount() {
    this.count = 0;
  }
}
</script>

model

input要素のコンポーネント化の際にvalueが競合しないように用いるmodelは
@Modelデコレータを使ってプロパティを定義します。

@Model(event?: string, options: (PropOptions | Constructor[] | Constructor) = {})

JavaScript

<script>
export default {
  name: 'MyRadio',
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: { type: Boolean }
  }
}
</script>

TypeScript

<script lang="ts">
import { Component, Model, Vue } from 'vue-property-decorator';

@Component
export default class MyCheckBox extends Vue {
  @Model('change', { type: Boolean }) readonly checked!: boolean;
}
</script>

watch

dataの変更を検知するWatchは@Watchデコレータを使ってメソッドを定義します。
optionにwatchオプションのimmediateやdeepもオブジェクトとして渡すことで指定できます。

@Watch(path: string, options: WatchOptions = {})

JavaScript

<script>
export default {
  name: 'InputText',
  data () {
    return {
      text: '',
      lengthDiff: 0
    }
  },
  watch: {
    text: function (newText, oldText) {
      this.lengthDiff = newText.length - oldText.length
    }
  }
}
</script>

TypeScript

<script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator';

@Component
export default class InputText extends Vue {
  text: string = '';
  lengthDiff: number = 0;

  @Watch('text')
  onTextChanged(newText: string, oldText: string) {
    this.lengthDiff = newText.length - oldText.length;
  }
}
</script>

provide, inject

深い階層でも親コンポーネントと子コンポーネントでデータを共有する際に用いるprovideとinjectは@provide, @injectデコレータで定義します。

@Provide(key?: string | symbol) 
@Inject(options?: { from?: InjectKey, default?: any } | InjectKey)

JavaScript

Parent.vue

<script>
export default {
  name: 'Parent',
  provide: {
    commonValue: 'foo'
  }
}
</script>

Child.vue

<script>
export default {
  name: 'Child',
  inject: {
    commonValue: { default: 'hoge' }
  }
}
</script>

TypeScript

Parent.vue

<script lang="ts">
import { Component, Provide, Vue } from 'vue-property-decorator';

@Component()
export default class Parent extends Vue {
  @Provide() commonValue = 'foo';
}
</script>

Child.vue

<script lang="ts">
import { Component, Inject, Vue } from 'vue-property-decorator';

@Component
export default class Child extends Vue {
  @Inject({ default: 'hoge' })
  readonly commonValue!: string;
}
</script>

mixins

コンポーネント間の共通処理を定義するミックスインはMixins()の継承を使って表現します。
ミックスイン自身もVueを継承したクラスとして定義します。
複数のミックスインを使う場合も、Mixins()の引数として与えることが可能です。
(最大5つ)
https://github.com/vuejs/vue-class-component/blob/master/src/util.ts#L35

JavaScript

mixinLogger.js

export default {
  created () {
    const now = new Date
    console.log(`created: ${now}`)
  },
  methods: {
    log (param) {
      console.log(`log: ${param}`)
    }
  }
}

Human.vue

<script>
import MixinLogger from './mixinLogger'

export default {
  name: 'Human',
  mixins: [MixinLogger],
  methods: {
    greeting () {
      console.log('おはよう')
      this.log('call greeting')
    }
  }
}
</script>

TypeScript

mixin.ts

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

@Component
export default class mixinLogger extends Vue {
  created() {
    const now = new Date;
    console.log(`created: ${now}`);
  }

  log(param) {
    console.log(`log: ${param}`);
  }
}

Human.vue

<script lang="ts">
import MixinLogger from './mixinLogger';
import { Component, Mixins } from 'vue-property-decorator';

@Component
export default class Human extends Mixins(MixinLogger) {
  greeting() {
    console.log('おはよう');
    this.log('call greeting');
  }
}
</script>

created, mounted, updated, destroyed ...etc

ライフサイクルフックはそのまま同名のメソッドとして宣言することですることで実装可能です。

JavaScript

<script>
export default {
  name: 'Human',
  created: function () {
    // 何か処理
  },
  mounted: function () {
    // 何か処理
  },
  updated: function () {
    // 何か処理
  },
  destroyed: function () {
    // 何か処理
  }
}
</script>

TypeScript

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';

@Component
export default class Human extends Vue {
  created() {
    // 何か処理
  }

  mounted() {
    // 何か処理
  }

  updated() {
    // 何か処理
  }

  destroyed() {
    // 何か処理
  }
}
</script>

参考

https://github.com/vuejs/vue-class-component
https://github.com/kaorun343/vue-property-decorator

676
604
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
676
604