Help us understand the problem. What is going on with this article?

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

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 になってるね
tokicat
TypeScript と Node.js が特にすきです React もすきです
bitkey
独自のキーテクノロジーを武器に事業を展開するスタートアップベンチャー
https://bitkey.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした