🎇

firebase v9でupdateが(少し)型安全になりました

2021/08/28に公開

先日ついにfirebase v9が リリースされました

知っている限り、v9ではモジュール式(ESM?)になっただけで、バンドルサイズの最適化以外の機能はないのですが、updateに関しては型定義での更新があったので紹介します。

v9の使い方

少しv9の使い方を紹介します。v8までのようにクラスで実装するとtree shakeしづらいので、全て関数になりました。

import { initializeApp } from "firebase/app";
const app = initializeApp({ projectId: "..." });
const DB = getFirestore(app);

const userDoc = doc(DB, "user", "userId");
setDoc(userDoc, { hoge: "fuga" });
updateDoc(userDoc, { piyo: "ponyo" });
deleteDoc(userDoc);
getDoc(userDoc);

わかりやすいですね。

updateで型がつく

本題です。これまじで感動したんですが、updateで型がつきます

type Room = {
  size: number;
  rooms: {
    living: number;
    dining: number;
    kitchen: number;
  };
  level1: {
    level2: { level3: string };
    level2_1: string[];
  };
};
const roomDocRef = doc(DB, "rooms", "roomId") as DocumentReference<Room>;
updateDoc(roomDocRef, { "rooms.living": 123 }); // ✅
updateDoc(roomDocRef, { "rooms.living": "abc" }); // ❌ 型 'string' を型 'number | FieldValue' に割り当てることはできません。
updateDoc(roomDocRef, { "level1.level2": { level3: "abc" } }); // ✅
updateDoc(roomDocRef, { "level1.level2": { level3: 123 } }); // ❌: 型 'number' を型 'string | FieldValue' に割り当てることはできません。
updateDoc(roomDocRef, { "level1.level2_1": arrayUnion("asd") }); // ✅
updateDoc(roomDocRef, { "rooms.living": increment(1) }); // ✅

DocumentReferenceがちゃんと型付けされていると、ネストしたプロパティまで推論されます。やばいです。圧倒的に型安全。typoで一日デバッグすることが無くなります。

ただし、ちょっと残念なのが、下の例のような場合です。

arrayUnionincrementなどの返り値は一律にFieldValueとなっているので、それぞれの区別がつきません。そのうえ、FieldValue型はどんなプロパティにも渡せます。だから例えば配列にincrementを渡してもエラーが出ないので注意が必要です。それと、nullundefinedFieldValue扱いになっているようでどのプロパティに渡しても受け入れられます。あまり過信するのは危険ですね。

updateDoc(roomDocRef, { "level1.level2_1": increment(243) }); // ✅ 🤔🤔🤔🤔🤔
updateDoc(roomDocRef, { "level1.level2_1": serverTimestamp() }); //✅ 🤔🤔🤔🤔🤔
updateDoc(roomDocRef, { "level1.level2_1": Timestamp.fromDate(new Date()) }); // ✅ 🤔🤔🤔🤔🤔
updateDoc(roomDocRef, { "level1.level2_1": null }); // ✅ 🤔🤔🤔🤔🤔
updateDoc(roomDocRef, { "level1.level2_1": undefined }); // ✅ 🤔🤔🤔🤔🤔

なお、batchrunTransactionでも同じでした。

変わらないところ

queryももしかしたら進化したかも!?と思ったら変わりませんでした。ジェネリクスでもないのでどうしようもないです。

const roomColRef = collection(
  DB,
  "rooms",
  "roomId"
) as CollectionReference<Room>;

const q = query(
  roomColRef,
  where("hogehoge", "==", "piyopiyo"), ✅ 🤔🤔🤔🤔🤔
  orderBy("fuga") ✅ 🤔🤔🤔🤔🤔
); 

Discussion