TypeScriptへの変換はConverter内部で行う。
read/writeともにassert関数で不正な値が混入しないか監視している。
FirestoreDataConverterはtofirestore, fromFirestoreのメソッドを持つオブジェクト。
これを○○Referenceに生えてるwithConverter関数に与えて、ミドルウェア処理を加えることが可能。
- toFirestore: addDoc関数やupdateDoc関数などのwrite処理に割り混む
- fromFireStore: getDoc関数のようなread処理に割り混む
fromFirestoreの途中、Timestamp型が扱いづらいのでDate型に変換している。
write側ではDate型をそのまま投げてもFirestore内部で自動的にTimestamp型に変換される。
snapshot.data({ serverTimestamps: "estimate" })
はserverTimestamp関数がnullになる問題を回避するため。(write時にTimestampは手元になく、サーバーの値を反映するまでラグがある。)
// src/lib/firebase.ts
import type { FirestoreDataConverter, QueryDocumentSnapshot, WithFieldValue } from "firebase/firestore";
const getConverter = <T extends object>(assert: (data: unknown) => asserts data is T): FirestoreDataConverter<T> => ({
toFirestore: (data: WithFieldValue<T>) => {
assert(data);
return data;
},
fromFirestore: (snapshot: QueryDocumentSnapshot) => {
const data = snapshot.data({ serverTimestamps: "estimate" });
const result = Object.fromEntries(
Object.entries(data).map(([key, value]) => {
if (typeof value.toString == "function" && value.toString().startsWith("Timestamp")) {
return [key, value.toDate()];
}
return [key, value];
})
);
assert(result);
return result;
},
});