# TypeScript のサポート

Vue CLI (opens new window) は、ビルトインの TypeScript ツールサポートを提供します。

# NPM パッケージ内の公式型宣言

静的型システムは、特にアプリケーションが成長するに伴い、多くの潜在的なランタイムエラーを防止するのに役立ち、これが Vue 3 が TypeScript で書かれている理由です。このことは、あなたが Vue 3 とともに TypeScript を使うために追加のツールを必要としないことを意味します - それは第一級市民 (first-class citizen) としてサポートを受けられます。

# 推奨される構成

// tsconfig.json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    // これは `this` のデータプロパティに対してより厳密な推論を可能にします
    "strict": true,
    "jsx": "preserve",
    "moduleResolution": "node"
  }
}
1
2
3
4
5
6
7
8
9
10
11

コンポーネントメソッドにおける this の型チェックを活用するために strict: true (もしくは少なくとも strict フラグの一部である noImplicitThis: true) を含める必要があることに注意してください。そうでないと、this は常に any 型として扱われます。

より詳細を知るためには、TypeScript compiler options docs (opens new window) を参照してください。

# 開発ツール

# プロジェクトの作成

Vue CLI (opens new window) は、TypeSript を使った新しいプロジェクトを作成できます。はじめるためには:

# 1. Vue CLI をまだインストールしていなければ、インストールします
npm install --global @vue/cli@next

# 2. 新しいプロジェクトを作成し、"Manually select features" を選択してください
vue create my-project-name

# もしすでに TypeScript をもたない Vue CLI で作成したプロジェクトがある場合、適切な Vue CLI プラグインを追加してください:
vue add typescript
1
2
3
4
5
6
7
8

コンポーネントの script の部分に言語として TypeScript が設定されていることを確認してください:

<script lang="ts">
  ...
</script>
1
2
3

# エディタによるサポート

TypeScript による Vue アプリケーションの開発のために、すぐに利用できる TypeScript サポートを提供している Visual Studio Code (opens new window) を強く推奨します。単一ファイルコンポーネント (SFCs) を使用している場合、SFC 内部での TypeScript の推論やその他の優れた機能を提供している、素晴らしい Vetur エクステンション (opens new window) を入手してください。

WebStorm (opens new window) もすぐに利用できる TypeScript と Vue のサポートを提供しています。

# Vue コンポーネントを定義する

TypeScript に Vue コンポーネントオブションのなかで適切に型を推論させるために、defineComponent グローバルメソッドでコンポーネントを定義する必要があります:

import { defineComponent } from 'vue'

const Component = defineComponent({
  // 型推論が有効になります
})
1
2
3
4
5

# オプション API とともに使用する

TypeScript は明示的に型を定義することなく、ほとんどの型を推論できるようにあるべきです。例えば、数値である count プロパティを持つコンポーネントがある場合、文字列に特有のメソッドを呼び出すとエラーになります:

const Component = defineComponent({
  data() {
    return {
      count: 0
    }
  },
  mounted() {
    const result = this.count.split('') // => 'split' プロパティは 'number' 型に存在しません
  }
})
1
2
3
4
5
6
7
8
9
10

複雑な型や推論の場合、タイプアサーション (type assertion) (opens new window) を使用してキャストすることができます:

interface Book {
  title: string
  author: string
  year: number
}

const Component = defineComponent({
  data() {
    return {
      book: {
        title: 'Vue 3 Guide',
        author: 'Vue Team',
        year: 2020
      } as Book
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 戻り値の型にアノテーションをつける

Vue の型宣言ファイルの循環的な性質により、TypeScript は算出プロパティの型を推論することが困難な場合があります。この理由により、算出プロパティの戻り値の型にアノテーションをつける必要があります。

import { defineComponent } from 'vue'

const Component = defineComponent({
  data() {
    return {
      message: 'Hello!'
    }
  },
  computed: {
    // アノテーションが必要です
    greeting(): string {
      return this.message + '!'
    }

    // セッターを持つ算出プロパティのでは、ゲッターにアノテーションが必要です
    greetingUppercased: {
      get(): string {
        return this.greeting.toUpperCase();
      },
      set(newValue: string) {
        this.message = newValue.toUpperCase();
      },
    },
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# Props にアノテーションをつける

Vue は type が定義されたプロパティについてランタイムバリデーションを行います。これらの型を TypeScript に提供するため、PropType を伴うコンストラクタをキャストする必要があります:

import { defineComponent, PropType } from 'vue'

interface ComplexMessage {
  title: string
  okMessage: string
  cancelMessage: string
}
const Component = defineComponent({
  props: {
    name: String,
    success: { type: String },
    callback: {
      type: Function as PropType<() => void>
    },
    message: {
      type: Object as PropType<ComplexMessage>,
      required: true,
      validator(message: ComplexMessage) {
        return !!message.title
      }
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

バリデータの型推論やメンバの補完が機能していない場合、引数に期待される型のアノテーションをつけることで問題に対処できるかもしれません。

# コンポジション API とともに使用する

On setup() function, you don't need to pass a typing to props parameter as it will infer types from props component option. setup() 関数においては、props 引数に型をつける必要はありません。setup() 関数は props コンポーネントオプションから型を推論するからです。

import { defineComponent } from 'vue'

const Component = defineComponent({
  props: {
    message: {
      type: String,
      required: true
    }
  },

  setup(props) {
    const result = props.message.split('') // 正しいです, 'message' は文字列 (string) として型づけされます
    const filtered = props.message.filter(p => p.value) // エラーが起こります: Property 'filter' does not exist on type 'string'
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# ref を型定義する

Refs infer the type from the initial value: Ref は初期値から肩を推論します:

import { defineComponent, ref } from 'vue'

const Component = defineComponent({
  setup() {
    const year = ref(2020)

    const result = year.value.split('') // => Property 'split' does not exist on type 'number'
  }
})
1
2
3
4
5
6
7
8
9

ときどき、ref の内部的な値の複雑な型を特定する必要があるかもしれません。デフォルトの推論をオーバーライドするために ref を呼び出すときに、単純にジェネリック引数を渡すことができます:

const year = ref<string | number>('2020') // year's type: Ref<string | number>
const year = ref<string | number>('2020') // year の型: Ref<string | number>

year.value = 2020 // OKです!
1
2
3
4

Note

ジェネリックの型が不明の場合、refRef<T> にキャストすることを推奨します。

# reactive を型定義する

reactive プロパティを型定義する場合、推論を使用できます:

import { defineComponent, reactive } from 'vue'

interface Book {
  title: string
  year?: number
}

export default defineComponent({
  name: 'HelloWorld',
  setup() {
    const book = reactive<Book>({ title: 'Vue 3 Guide' })
    // もしくは
    const book: Book = reactive({ title: 'Vue 3 Guide' })
    // もしくは
    const book = reactive({ title: 'Vue 3 Guide' }) as Book
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 算出プロパティを型定義する

算出プロパティの値は返り値の型から自動的に推論します:

import { defineComponent, ref, computed } from 'vue'

export default defineComponent({
  name: 'CounterButton',
  setup() {
    let count = ref(0)

    // 読み取り専用
    const doubleCount = computed(() => count.value * 2)

    const result = doubleCount.value.split('') // Property 'split' does not exist on type 'number'
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13

Deployed on Netlify.
最終更新日: 9/22/2020, 12:35:49 AM