LoginSignup
0

More than 1 year has passed since last update.

posted at

updated at

Nuxt.js + TypeScriptで空のモデルを表現する方法

はじめに

エキサイトでエンジニアのインターンをしている山縣です。

Webアプリケーションの制作において、アンケートフォームや管理画面でのフォームなどでなんらかのフォームを作ることは少なくないと思います。本記事では、Nuxt.jsとTypeScriptを使用した開発環境において、空のモデルを表現する方法についてフォームを題材に紹介します。

本記事で扱うフォームについて

本記事では、サンプルとしてフォームにnameitemをもつモデルを扱います。
ディレクトリ構成は、弊社Web・iOSエンジニアの三浦さんがこちらの記事でまとめています。

Nuxt.js + TypeScriptのアーキテクチャ一例

export class UserForm {
  name: string
  item: string

  constructor(name: string, item: string) {...}
}

1. フォームをユニオン型で表現する

フォームをユニオン型で表現する場合、下記のようなコードになります。

ユニオン型について↓
判別可能なUnion型 - TypeScript Deep Dive 日本語版

<script lang=ts>
interface DataType {
  userForm: UserForm | null
}

export default Vue.extend({
  data(): DataType {
    return {
      userForm: null,
    }
  },
})
</script>

このようなコードを書くことで、例えばモーダル上にフォームを実装したとき、下記のような処理を書くことができます。

  • モーダルが開かれるまではuserFormをnullとして扱う
  • モーダルが開かれた時にはフォームを初期化する( this.userForm = new UserForm(...) )
  • モーダルを閉じる時はuserFormをnullにする

利点

現在フォームに値が入力されているかどうかをnullで判別することができます。

欠点

TypeScriptを記述する<script>内では特に問題がありません。しかし、<template>内において以下のような問題が発生してしまいます。
userFormをnullとして扱っているため、v-model="userForm.name"と記述している箇所がnull.nameとなってしまう可能性があり、nullの時にエラーとなってしまいます。そのため、computed内でnullである可能性を排除しなくてはなりません。今回示したサンプルでは、フォームのフィールド数が少ないため、computedに新たに関数を追加するコストとはそこまで大きくありませんが、いくつも入力欄があるとその都度computedに関数を追加しないといけないため非常に面倒です。

2. フォームをオプショナル型で表現する

フォームをオプショナル型で表現する場合、下記コードのように変数名の後ろに?を付与します。nullとundefinedの違いについては省略しますが、1と同ような利点・欠点があります。

interface DataType {
  userForm?: UserForm
}

3. フォームをクラスのみで表現する

フォームをクラスのみで表現する場合、下記のようなコードになります。

interface DataType {
  userForm: UserForm
}

利点

フォームをクラスのみで表現したときの利点は下記のとおりです。nullを扱わないため、v-modelを安全に利用することができます。

  • nullを扱わないため、1の欠点を解消できる
  • nullを扱わないコードになる

欠点

下記に欠点をまとめました。nullやundefinedを使用しないことで面倒になってしまうことも多くあります。

  • 初期化する都度、new UserForm(...)とタイプするのが面倒
  • 入力欄が増えた際に、初期化している箇所すべてに手を加えるのが面倒
  • 誤って意図しない初期値をコンストラクタに入れてしまった場合に気づきにくい
  • nullで判断していた箇所と同じことをするのは大変

3の欠点を解消した方法

UserFormクラスに初期化するためのstaticメソッドを実装しました。
これにより、初期化の際にはUserForm.init()と呼び出すことで意図しない初期値の混入を防ぐことができるようになります。
また、フォームに値が入力されたかどうかをUserFormに記述することができたりします。


export class UserForm {
  name: string
  item: string

  constructor(name: string, item: string) {...}

  static init(): UserForm {
    return new UserForm('', '')
  }
}

モデルに初期化用の関数を追加せずに、Vueコンポーネント内に同様の記述をすることも考えましたが、入力欄が増えたときはモデルに手が加えられるため、モデルに近い場所に初期化用の関数を追加するのが望ましいと判断しました。

このような実装を調べてみると、例えばJavaのカレンダークラスを利用する際は、Calendar now = Calendar.getInstance(); と書くようです。

Calendar (Java Platform SE 8 )

結論

上記にまとめた3の書き方を取り入れてフォームを実装することにしました。これにより、フォームの初期化をしやすくなり、nullを使用しないコードを書くことができるようになります。

ここまでお付き合いいただきありがとうございました!

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
What you can do with signing up
0