Skip to content
177 changes: 162 additions & 15 deletions src/guide/typescript-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,31 @@

より詳細を知るためには、[TypeScript compiler options docs](https://www.typescriptlang.org/docs/handbook/compiler-options.html) を参照してください。

## Webpack の設定

カスタムの Webpack の設定を使っている場合、 `.vue` ファイルの `<script lang="ts">` ブロックをパースするように `ts-loader` を設定する必要があります:

```js{10}
// webpack.config.js
module.exports = {
...
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/],
},
exclude: /node_modules/,
},
{
test: /\.vue$/,
loader: 'vue-loader',
}
...
```

## 開発ツール

### プロジェクトの作成
Expand All @@ -51,9 +76,17 @@ vue add typescript
</script>
```

また、TypeScript と [JSX `render` 関数](/guide/render-function.html#jsx) を組み合わせたい場合:

```html
<script lang="tsx">
...
</script>
```

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

TypeScript による Vue アプリケーションの開発のために、すぐに利用できる TypeScript サポートを提供している [Visual Studio Code](https://code.visualstudio.com/) を強く推奨します。[単一ファイルコンポーネント](./single-file-components.html) (SFCs) を使用している場合、SFC 内部での TypeScript の推論やその他の優れた機能を提供している、素晴らしい [Vetur エクステンション](https://github.com/vuejs/vetur) を入手してください。
TypeScript による Vue アプリケーションの開発のために、すぐに利用できる TypeScript サポートを提供している [Visual Studio Code](https://code.visualstudio.com/) を強く推奨します。[単一ファイルコンポーネント](./single-file-component.html) (SFCs) を使用している場合、SFC 内部での TypeScript の推論やその他の優れた機能を提供している、素晴らしい [Vetur エクステンション](https://github.com/vuejs/vetur) を入手してください。

[WebStorm](https://www.jetbrains.com/webstorm/) もすぐに利用できる TypeScript と Vue のサポートを提供しています。

Expand All @@ -69,6 +102,18 @@ const Component = defineComponent({
})
```

[単一ファイルコンポーネント](/guide/single-file-component.html) を使っている場合、これは一般的に次のように書かれます:

```vue
<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
// type inference enabled
})
</script>
```

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

TypeScript は明示的に型を定義することなく、ほとんどの型を推論できるようにあるべきです。例えば、数値である `count` プロパティを持つコンポーネントがある場合、文字列に特有のメソッドを呼び出すとエラーになります:
Expand Down Expand Up @@ -108,6 +153,52 @@ const Component = defineComponent({
})
```

### `globalProperties` のための型の拡張

Vue 3 には [`globalProperties` オブジェクト](../api/application-config.html#globalproperties) が用意されていて、任意のコンポーネントインスタンスからアクセス可能なグローバルプロパティを追加するために使用できます。例えば、 [プラグイン](./plugins.html#プラグインを書く) では共有されたグローバルオブジェクトや関数を注入したい場合があります。

```ts
// ユーザの定義
import axios from 'axios'

const app = Vue.createApp({})
app.config.globalProperties.$http = axios

// あるデータを検証するためのプラグイン
export default {
install(app, options) {
app.config.globalProperties.$validate = (data: object, rule: object) => {
// 対象のデータが特定のルールを満たしているかチェック
}
}
}
```

これらの新しいプロパティを TypeScript に伝えるために、[Module Augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation) を使うことができます。

上記の例では、次のような型宣言を追加することができます:

```ts
import axios from 'axios'

declare module '@vue/runtime-core' {
export interface ComponentCustomProperties {
$http: typeof axios
$validate: (data: object, rule: object) => boolean
}
}
```

この型宣言は同じファイル、またはプロジェクト全体の `*.d.ts` ファイル(例えば、 TypeScript で自動的に読み込まれる `src/typings` フォルダの中)に記述することができます。ライブラリやプラグインの作者は、このファイルを `package.json` の `types` プロパティで指定します。

::: warning 宣言ファイルが TypeScript モジュールであることを確認
Module Augmentation を利用するためには、ファイルの中に少なくとも1つのトップレベルの `import` か `export` があることを確認する必要があります。それが単に `export {}` であってもです。

[TypeScript](https://www.typescriptlang.org/docs/handbook/modules.html) では、トップレベルの `import` や `export` を含むファイルはすべて「モジュール」とみなされます。モジュールの外で型宣言が行われた場合、元の型を拡張するのではなく、上書きしてしまいます。
:::

`ComponentCustomProperties` 型について詳しくは、[`@vue/runtime-core` での定義](https://github.com/vuejs/vue-next/blob/2587f36fe311359e2e34f40e8e47d2eebfab7f42/packages/runtime-core/src/componentOptions.ts#L64-L80) と、[TypeScript ユニットテスト](https://github.com/vuejs/vue-next/blob/master/test-dts/componentTypeExtensions.test-d.tsx) を参照してください。

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

Vue の型宣言ファイルの循環的な性質により、TypeScript は算出プロパティの型を推論することが困難な場合があります。この理由により、算出プロパティの戻り値の型にアノテーションをつける必要があります。
Expand All @@ -125,7 +216,7 @@ const Component = defineComponent({
// アノテーションが必要です
greeting(): string {
return this.message + '!'
}
},

// セッターを持つ算出プロパティのでは、ゲッターにアノテーションが必要です
greetingUppercased: {
Expand All @@ -134,8 +225,8 @@ const Component = defineComponent({
},
set(newValue: string) {
this.message = newValue.toUpperCase();
},
},
}
}
}
})
```
Expand All @@ -147,34 +238,91 @@ Vue は `type` が定義されたプロパティについてランタイムバ
```ts
import { defineComponent, PropType } from 'vue'

interface ComplexMessage {
interface Book {
title: string
okMessage: string
cancelMessage: string
author: string
year: number
}

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
book: {
type: Object as PropType<Book>,
required: true
}
}
})
```

::: warning
TypeScript には、関数式の型推論に [設計上の制限](https://github.com/microsoft/TypeScript/issues/38845) があるため、 `validators` と、オブジェクトや配列の `default` 値に注意する必要があります:
:::

```ts
import { defineComponent, PropType } from 'vue'

interface Book {
title: string
year?: number
}

const Component = defineComponent({
props: {
bookA: {
type: Object as PropType<Book>,
// 必ずアロー関数を使うこと
default: () => ({
title: 'Arrow Function Expression'
}),
validator: (book: Book) => !!book.title
},
bookB: {
type: Object as PropType<Book>,
// または明示的にこのパラメータを提供する
default(this: void) {
return {
title: 'Function Expression'
}
},
validator(this: void, book: Book) {
return !!book.title
}
}
}
})
```

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

発行されたイベントのペイロードにアノテーションをつけることができます。また、すべての宣言されていない発行されたイベントは、呼び出されたときに型エラーが発生します:

```ts
const Component = defineComponent({
emits: {
addBook(payload: { bookName: string }) {
// ランタイムバリデーションの実行
return payload.bookName.length > 0
}
},
methods: {
onSubmit() {
this.$emit('addBook', {
bookName: 123 // 型エラー!
})

this.$emit('non-declared-event') // 型エラー!
}
}
})
```

## コンポジション 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` コンポーネントオプションから型を推論するからです。

```ts
Expand All @@ -197,7 +345,6 @@ const Component = defineComponent({

### `ref` を型定義する

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

```ts
Expand Down