LoginSignup
8
3

More than 5 years have passed since last update.

[vue.js] コンポーネントのpropsにもっとちゃんと型をつけたい

Posted at

TL, DR

コンポーネントのpropsにより厳格な型を指定するためのライブラリ vue-strict-prop をつくりました。
意見などもらえると喜びます。

問題

Vue 2.5からTypeScript向けの型定義が大きく改善され、コンポーネントのpropsの型もコンポーネントオプションを元に推論してくれるようになりました。

例えばこんな感じ

export default Vue.extend({
  name: "ExampleComponent",
  template: "...",
  props: {
    // titleの型はstringとみなされる
    title: String,

    // itemsの型はany[]とみなされる
    items: { type: Array, required: true },

    // filterの型は (...args: any[]) => any とみなされる
    filter: { type: Function, required: true },

    // directionの型はstringとみなされる
    direction: {
      type: String,
      default: "horizontal",
      validator: v => v === "horizontal" || v === "vertical"
    }
  }
});

しかし、この推論結果について、以下のような点が気になります。

  • title には requireddefault も指定されていないので、値が入らないケースがある。
    つまり、本当は string ではなくて string | undefined になってほしい
  • items は配列だけど、できれば要素の型も指定したい
  • filter は関数だけど、正確なシグネチャ(例えば (value: string) => boolean とか)を指定したい
  • direction は、string ではなく "horizontal" | "vertical" になってほしい

vue-strict-prop

これを改善するべく、vue-strict-prop というちょっとしたライブラリを作りました。
これを使うと、上のコードは下のようになります。

import p from "vue-strict-prop"

export default Vue.extend({
  name: "ExampleComponent",
  template: "...",
  props: {
    // titleの型はstring | undefinedとみなされる
    title: p(String).optional,
    // itemsの型はstring[]とみなされる
    items: p.ofArray<string>().required,
    // filterの型は (value: string) => boolean とみなされる
    filter: p.ofFunction<(value: string) => boolean>().required,
    // directionの型は"horizontal" | "vertical"とみなされる
    direction: p.ofStringLiterals("horizontal", "vertical").default("horizontal")
  }
});

使い方

基本のパターン。型を指定した後、optionalrequireddefaultのどれかを指定します。
optionalrequireddefault のどれかで終わるのは、以下すべてのパターンで共通

import p from "vue-strict-props";

p(TYPE).optional        // { type: TYPE }
p(TYPE).required        // { type: TYPE, required: true }
p(TYPE).default(VALUE)  // { type: TYPE, default: VALUE }

validator を指定したい場合はこう

p(String).validator(v => v.length < 3).required

複数の型を指定するパターン。今のところ指定できるのは5つまで

p(TYPE1, TYPE2).optional

ArrayやFunctionなどに詳細な型をつけるために、それぞれメソッドが用意されています。

p.ofArray<string>().required
// Array ではなく ReadonlyArrayを使う場合はofRoArrayで
p.ofRoArray<string>().required
p.ofFunction<() => void>().required
p.ofObject<{ foo: string }>().required
// 型が"foo" | "bar"になるだけでなく、`value in ("foo", "bar")` 相当のvalidatorも登録される
p.ofStringLiterals("foo", "bar").required

型指定なしも

p.ofAny().required

or を使った条件の結合
6つ以上の型を指定したい場合(ないと思うけど)も or を使います

p(String).or.ofFunction<() => string>().required
p(TYPE1, TYPE2, TYPE3, TYPE4, TYPE5).or(TYPE6, TYPE7).required
8
3
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
8
3