TypeScript+Nuxt.js等で詰まったところ

仕事で本格的にTypeScriptを使うことになりそうなので色々調査したりしているが、調べている過程でうまくいかないところがいくつかあったので簡単にまとめておく。

Nuxt.js+TypeScript+Jestでのエラー

以下のVueファイルと、TypeScriptで書かれたテストコードがある。

page1.vue

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

export default Vue.extend({
  data() {
    return {
      test: '',
    }
  },
})
</script>

page1.spec.ts

import { mount } from '@vue/test-utils'
import Page1 from '@/pages/page1.vue'

describe('Page1', () => {
  test('is a Vue instance', () => {
    const wrapper = mount(Page1)
    expect(wrapper.vm).toBeTruthy()

    expect(wrapper.vm.test).toEqual('')
  })
})

Vueファイルのインポート部分でエラーが出るが、これは型宣言の追加で解決できる(以下の型宣言追加箇所を参照)。

セットアップ - Nuxt TypeScript

また、describe等のエラーは@types/jestを追加してtsconfig.jsontypesjestを追加することで解決できる。

ただ、wrapper.vm.testのエラーだけが解決できない(testというプロパティが存在しないと言われる)。調べた限りではこれの解決方法は2つあった。

1. any型として扱う

以下のように記述することで、少なくとも実行は出来るようになった。

expect((wrapper.vm as any).test).toEqual('')

ただしこれをやると型補完が利かなくなる(wrapper.vm.まで打ち込んでもtestが候補に出てこない)。

2. interface等を使う

interface等を使ってtestというプロパティが存在することを明示的に宣言してやる(出典がどこかは忘れた)。ただVueファイルを作成する度にこれらを宣言するのは心が折れるため、結局試すこと自体しなかった。そもそも出典がどこかも忘れたため、本当にそう書けるかどうかも分からない。

結論

JavaScriptだと普通に動くのでテストコードはJavaScriptで書くことを提案した。そもそもよく考えたら注目すべきは画面側の振る舞いであって内部パラメータにアクセスすること自体不要な気がしてきた。フロントエンドのテストコードをよく分かっていないので何とも言えないが。

型の指定方法

以下のようなファイルがある。

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

export interface Interface1 {
  a: string
}

export interface Interface2 {
  a: string
}

export default Vue.extend({
  data(): { test: Interface2 } {
    return {
      test: { a: 'a' },
    }
  },
  mounted() {
    this.method1(this.test)
  },
  methods: {
    method1(arg1: Interface1) {
      return arg1.a
    },
  },
})
</script>

method1Interface1を引数としているがmountedで実行される際の引数testInterface2のため、コンパイルエラーが発生するものだと思っていた。ただ、これは問題なく実行できる。

Javaだとインターフェース名が異なれば別のもの扱いだがTypeScriptだと中のプロパティを確認するようなので、同一プロパティを持っていれば問題なく実行できるらしい。そういうように解釈した。


他にもいくつかあったがエディタを変えたら再現しなくなったものとかもありうまくまとめられなかった。また何か見つけたらまとめるかもしれない。