LoginSignup
20
16

More than 5 years have passed since last update.

Vue + TypeScript を模索して迷走した先にあるもの

Posted at

これは 2019.01.29 スタートアップテック vol.2 の LT 資料です

@zaru

Vue で TypeScript を使いたい

Vue は楽しいです。TypeScript も楽しいです。楽しい * 楽しいにしたいです。

現状確認および課題

  • Vue だけであれば VueCLI で TypeScript サポート選べば OK
  • Vuex も TypeScript で書ける
    • けどコンポーネントからの読み出しは恩恵を受けにくい
  • Nuxt も v2.5 から TypeScript サポートが良くなる
    • 初期設定なしですぐ書けるようになる
  • Vue template 内でのサジェストが弱い…

今回の目標

  • とにかくサジェストされてほしい。いつでもどこでも

まずは VueCLI で TypeScript / Class スタイルな設定でプロジェクトを作る

$ vue create ts-proj
? Check the features needed for your project:
#=> Babel, TypeScript, Router, Vuex あたり

? Use class-style component syntax?
#=> Yes

? Use Babel alongside TypeScript for auto-detected polyfills?
#=> Yes
<template>
  <div class="home">
    <ul>
      <li v-for="todo in todos" :key="todo.id">{{todo.content}}</li>
    </ul>
  </div>
</template>

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

interface Todo {
  id: number
  content: string
}

@Component({})
export default class Home extends Vue {
  @Provide() todos: Todo[]
}
</script>

普通の SFC で定義した配列

1.gif

サジェストされてる! (なぜか VScode はされなかった…)

次は vuex で試してみる。 store.ts に適当に state を生やしてみる。

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

interface VuexTodo {
  id: number
  content: string
}

export interface State {
  vuex_todos: VuexTodo[]
}

export const state: State = {
  vuex_todos: []
}

export default new Vuex.Store({ state })

適当に shims-vue.d.ts とかで declare 拡張しておく

import Vue from 'vue'
import * as Vuex from 'vuex'
import * as Store from './store'

declare module 'vue/types/vue' {
  interface Vue {
    $store: Vuex.Store<any>,
    $state: Store.State
  }
}
<template>
  <div class="home">
    <ul>
      <li v-for="todo in allTodo" :key="todo.id">{{todo.content}}</li>
    </ul>
  </div>
</template>

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

  @Component({})
  export default class Home extends Vue {
    get allTodo () {
      return this.$state.vuex_todos
    }
  }
</script>

this.$state 経由は拡張しているのでサジェストされる。でも template 内だとされない

2.gif

あと this.$store 経由の getters などはサジェストされない ( any にしてるから… )

state はサジェストされるが… getters this.$store.getters['getAllTodo'] とかは厳しい。そこで次は vuex-module-decorators を入れてみる

this.$store 経由ではアクセスしないので shims-vue.d.ts を修正

declare module '*.vue' {
  import Vue from 'vue'
  export default Vue
}
import { Module, VuexModule, getModule } from 'vuex-module-decorators'
import store from "@/store"

interface ModuleTodo {
  id: number
  content: string
}
export interface ITodo {
  module_todos: ModuleTodo[]
}

@Module({ dynamic: true, store, name: "counter", namespaced: true })
class Todo extends VuexModule implements ITodo{
  module_todos: ModuleTodo[] = [] // state

  get getAllModuleTodo () { // getter
    return this.module_todos
  }
}

export const storeTodo = getModule(Todo)

Vuex store 初期化

import Vue from 'vue'
import Vuex from 'vuex'

import { ITodo } from './store/todo'

Vue.use(Vuex)

export interface State {
  todo: ITodo
}
export default new Vuex.Store<State>({})

コンポーネント側で読み込んで使う。


import {Component, Provide, Vue} from 'vue-property-decorator';
import {storeTodo} from '@/module/todo'

@Component({})
export default class Home extends Vue {
  get allTodo () {
    return storeTodo.getAllModuleTodo
  }
}

これで getters とか actions もサジェストされる!

3.gif

でも template ではまだサジェストされない

次は template でもサジェストがほしい。というわけで jsx (tsx) で書くようにしてみる。 @vue/cli-plugin-babel が必要

tsconfig.json で設定

{
  "compilerOptions": {
    "jsx": "preserve",
    "jsxFactory": "h",
    // ...
  }
}

Home.tsx


import { VNode, CreateElement } from 'vue';
import { Component, Vue } from 'vue-property-decorator';
import { storeTodo } from '@/module/todo'

@Component
export default class Todo extends Vue {
  public render(h: CreateElement): VNode {
    return <div>
      <ul>
        {storeTodo.getAllModuleTodo.map(todo =>
          <li>{todo.content}</li>
        )}
      </ul>
    </div>
  }
}

これで template でもサジェストされた!最高!
( JSX だから当然だけど )

4.gif

注意

  • JSX 採用すると Vue 独自の便利機能が使えない
    • v-model とかイベント系を自前で実装する必要がある
    • vue/jsx が beta だけど一応対応実装進めているので時間の問題?
20
16
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
20
16