Firestore.Timestamp って、いらなくね?
ちゃんと使いこなせばメリットもあるんだろうなぁと思いつつ・・・
少なくとも小規模なプロジェクトでは、Timestamp型が存在するせいで
- Firestore から読んだ、時刻フィールドを toDate() で Date型にもどす
- Document の interface と、 REST をまたぐ interface を分ける
みたいな対応が必要になるわけです。いちいちめんどいんすこれ。
Date 型で十分な状況もあるんです。
問題の例
interfaceUser{name:string;updatedAt:Date;}constwrite:User={name:"taro",updatedAt:Date.now(),};awaitfirestore.collection("users").doc(write.name).set(write);constread:User=awaitfirestore.collection("users").doc(write.name).get().then(dss=>dss.data());console.log(read);// updatedAt が Timestamp クラスになってるよ!
魔術の源: Timestamp を Date へ再帰的に変換するヘルパーメソッド
functiontimestampToDateRecursively(value:any):any{if(value==null){returnvalue;}elseif(value.constructor===Firestore.Timestamp){returnvalue.toDate();}elseif(Array.isArray(value)){returnvalue.map(timestampToDateRecursively);}elseif(value.constructor===Object){constconverted:any={};for(constkeyinvalue){converted[key]=timestampToDateRecursively(value[key]);}returnconverted;}else{returnvalue;}}
白魔術: いちいちヘルパーメソッドをかませる
- どこで何が起きてるかわすりやすい。安全。
- いちいち忘れたりする。めんどい。
constread:User=awaitfirestore.collection("users").doc(write.name).get().then(dss=>timestampToDateRecursively(dss.data()));// 毎回書く必要あり console.log(read);// updatedAt がちゃんと Date になってるね
黒魔術: DocumentSnapshot.data() をオーバーライドする
- 意識しなくても勝手に変換されてる。便利。
- 知らないと、Firestoreの仕様の誤解や混乱のもとになる。危険。
/**
* DocumentSnapShot.data() で返すすべてのTimestamp型をあらかじめDate型へ変換するよう
* プロトタイプをオーバーライドします
*/functionwrapDocumentSnapshotData(){console.log(`Wrapping DocumentSnapshot.data()`);constorigin=Firestore.DocumentSnapshot.prototype.data;Firestore.DocumentSnapshot.prototype.data=function(){constdata=origin.bind(this)();constconverted=timestampToDateRecursively(data);// ここ!returnconverted;};}wrapDocumentSnapshotData();constread:User=awaitfirestore.collection("users").doc(write.name).get().then(dss=>dss.data());// いちいち意識しなくていいconsole.log(read);// updatedAt がちゃんと Date になってるね