9
6

More than 3 years have passed since last update.

Firestore.Timestamp に触れたくないあなたのための黒魔術

Last updated at Posted at 2020-04-22

Firestore.Timestamp って、いらなくね?

ちゃんと使いこなせばメリットもあるんだろうなぁと思いつつ・・・
少なくとも小規模なプロジェクトでは、Timestamp型が存在するせいで

  • Firestore から読んだ、時刻フィールドを toDate() で Date型にもどす
  • Document の interface と、 REST をまたぐ interface を分ける

みたいな対応が必要になるわけです。いちいちめんどいんすこれ。
Date 型で十分な状況もあるんです。

問題の例

interface User {
  name: string;
  updatedAt: Date;
}

const write: User = {
  name: "taro",
  updatedAt: Date.now(),
};
await firestore
  .collection("users")
  .doc(write.name)
  .set(write);

const read: User = 
  await firestore
    .collection("users")
    .doc(write.name)
    .get()
    .then(dss=>dss.data());

console.log(read); // updatedAt が Timestamp クラスになってるよ!

魔術の源: Timestamp を Date へ再帰的に変換するヘルパーメソッド

function timestampToDateRecursively(value: any): any{
  if (value == null) {
    return value;
  } else if (value.constructor === Firestore.Timestamp) {
    return value.toDate();
  } else if (Array.isArray(value)) {
    return value.map(timestampToDateRecursively);
  } else if (value.constructor === Object) {
    const converted: any = {};
    for (const key in value) {
      converted[key] = timestampToDateRecursively(value[key]);
    }
    return converted;
  } else {
    return value;
  }
}

白魔術: いちいちヘルパーメソッドをかませる

  • どこで何が起きてるかわすりやすい。安全。
  • いちいち忘れたりする。めんどい。
const read: User = 
  await firestore
    .collection("users")
    .doc(write.name)
    .get()
    .then(dss=>timestampToDateRecursively(dss.data())); // 毎回書く必要あり 

console.log(read); // updatedAt がちゃんと Date になってるね

黒魔術: DocumentSnapshot.data() をオーバーライドする

  • 意識しなくても勝手に変換されてる。便利。
  • 知らないと、Firestoreの仕様の誤解や混乱のもとになる。危険。
/**
 * DocumentSnapShot.data() で返すすべてのTimestamp型をあらかじめDate型へ変換するよう
 * プロトタイプをオーバーライドします
 */
function wrapDocumentSnapshotData() {
  console.log(`Wrapping DocumentSnapshot.data()`);
  const origin = Firestore.DocumentSnapshot.prototype.data;
  Firestore.DocumentSnapshot.prototype.data = function () {
    const data = origin.bind(this)();
    const converted = timestampToDateRecursively(data); // ここ!
    return converted;
  };
}

wrapDocumentSnapshotData();

const read: User = 
  await firestore
    .collection("users")
    .doc(write.name)
    .get()
    .then(dss=>dss.data()); // いちいち意識しなくていい

console.log(read); // updatedAt がちゃんと Date になってるね
9
6
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
9
6