0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TypeScriptでローカル用とサーバ送信用の微妙に構造の異なるクラスをデコレータでいい感じに変換する。

Last updated at Posted at 2020-04-28

##記事のデータ構造を表すクラスがある

class Article {
  public title: string = '' // タイトル
  public body: string = '' // 内容
  public caretPosition: number = 0 // キャレット位置
}

こんな感じでの記事の「タイトル」「内容」「キャレット位置」をフィールドに持つクラスがあり、ローカルで記事の内容を保持するために利用し、APIでサーバにもそのまま送信したいとします。

##「キャレット位置」はサーバに送りたく無い
しかし、ここでcaretPositionについては、ローカルでの処理にしか使わないフィールドなのでサーバには送りたく無かったとします。
これをそのままfetchで送ってしまうと、当然のことながらサーバに対してcaretPositionが含まれたオブジェクトが送られてしまうので、どうにかしてcaretPositionを取り除いてから送信する必要があります。

##素直なやり方

const article = new Article()
const articleRemote = {
  title: article.title,
  body: article.body
}
// fetchにarticleRemoteを渡す

必要フィールドのみを詰め直す処理を別途記述するとどうでしょうか。
クラス定義とは遠い場所での処理になるため、クラス定義の変更に対して追随し忘れたりが発生しそうです。

##デコレータとメタデータを使って処理

class Article {
  public title: string = ''
  public body: string = ''
  @LocalOnly
  public caretPosition: number = 0
}

こんな感じでクラス定義にサーバに送りたく無いフィールドに対してデコレータで指定できると便利です。

##デコレータを機能するようにする
では実際にLocalOnlyデコレータが機能するようにしてみましょう。
npm install reflect-metadataでreflect-metadataを導入しておきましょう。

import 'reflect-metadata'

const symbolLocalOnly = Symbol('LocalOnly')

// デコレータ定義。対象フィールドにLocalOnlyのメタデータを付与する。
function LocalOnly(target: any, props: string) {
  Reflect.defineMetadata(symbolLocalOnly, true, target, props)
}

class Article {
  public title: string = ''
  public body: string = ''
  @LocalOnly
  public caretPosition: number = 0
}

// LocalOnlyフィールド削除関数(実際は再帰的にオブジェクトを辿るようにする)
function removeLocalOnly(data: any): any {
  const ret: any = {}
  Object.keys(data).forEach(key => {
    // LocalOnlyのメタデータが付与されていないものだけを処理
    if (!Reflect.hasMetadata(symbolLocalOnly, data, key)) {
      ret[key] = data[key]
    }
  })
  return ret
}

これにより

const article = new Article()
const articleRemote = removeLocalOnly(article)
// fetchにarticleRemoteを渡す

と詰め直す処理を書かずに、クラス定義に指定をまとめることができます。

##まとめ
ローカル用とサーバ送信用の微妙に構造の異なるデータを取り扱うケースは結構あると思います。
そんな時はデコレータを利用して不要なフィールドを指定できると直感的だよというお話でした。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?