TypeScript
vue.js

Vue + TypeScriptでpropsのObjectやArrayに型をつける

More than 1 year has passed since last update.


Vue + TypeScriptでのpropsの推論

Vue 2.5でTypeScriptのサポートが強化されました。

その1つがpropsの推論で、propsにStringNumberなどと指定すると、それらの値をstring型、number型として利用できます。しかしArrayObjectは、any[]型、any型になってしまいます。

// 適当なクラス

class Foo {}

Vue.extend({
props: {
str: String,
num: Number,
foo: Foo, // カスタムコンストラクタ
arr: Array,
obj: Object,
},
created() {
this.str // string型
this.num // number型
this.foo // Foo型
this.arr // any[]型 <- この2つを
this.obj // any型 <- 何とかしたい
},
}

Fooのようなカスタムコンストラクタには対応していますが、Objectにはやはりtypeinterfaceを使って指定したいです。


ArrayとObjectにも型の指定を

Vueの型定義を読んでいると、型キャストを利用してArrayObjectにも型を指定できることを発見しました。方法は簡単で、string[]型を利用したい部分にArray as () => string[]を指定します。(下の例ではPropを定義してそれを使っています)

// Vueのpropの型を作成するための型

type Prop<T> = () => T

// 適当なインターフェース
interface Bar {}

Vue.extend({
props: {
arr: Array as Prop<string[]>,
obj: Object as Prop<Bar>,
// `Function as Prop<() => void>`ではエラーがでるため、一度anyを経由させる
fnc: Function as any as Prop<() => void>
// 省略可能なプロパティを指定する時にも利用できる
optional: {
type: String as Prop<string | undefined>,
required: false,
},
},
created() {
this.arr // string[]型
this.obj // Bar型
this.fnc // (() => void)型
this.optional // (string | undefined)型
},
})

Functionas any asで格好悪いことになってますが、ひとまず任意の型を指定することができました。

一方で、型のキャストしか行っていないので、実行時のJavaScriptに余分な動作が入るなどといったことはありません。(個人的に重要なポイント)


仕組み

Vueの型定義がStringからstring型を取得する仕組みを悪用しました。JavaScriptではString()で文字列を、Number()で数字を、Array()で配列を取得できます。propsはこれを利用してstring型、number型、any[]型を推論しています。

今回はArray as () => string[]をすることでArray()が「配列: string[]型」なのだと勘違いさせています。


さいごに

Vueの型定義弄って直接Array as string[]と指定できないかと試したのですが、そもそもTypeScript側のエラーで直接キャストできずArray as any as string[]としないとダメでした。残念。1

しかし、Array as Prop<string[]>で簡単にArrayObjectに型を指定できるので、Vue + TypeScriptを使用する場合はぜひ試してみてください。





  1. 一応Array as any as string[]でいいなら出来たのですが、Array as Prop<string[]>の方がシンプルなので、お蔵入りにします。