*こちらの資料 で解決できなかったと記載したfirebase周りの型解決についての記事になります
こちらの資料を元にした記述があるので、目を通してもらえると理解しやすいかと思います
なにがやりたいか
firebaseのFirestoreへのアクセスする処理をfirebase functionsとフロントで使いまわしたい
何が問題か
firestoreの型定義がブラウザ向けとfunctions向けで別物になっていて、ブラウザ向けは lib.dom.d.tsへ依存しているなど、トランスパイル時に両方を満たすうまい方法が見つけられなかった
firebaseのjs向けsdkは、ブラウザ環境で利用するための firebase
パッケージと、node環境で利用するための firebase-admin
パッケージがあります。
これらは共に Firestore
クラスの定義を(何故か)それぞれ持っています
またそれらは、例えばServiceWorkerのような環境に依存する値に依存しています
つまり、いわゆるRepository層を作ってそれをfirebase functionsとフロント双方で使おうとするとTypeScriptのトランスパイル時に型検査エラーとなります
今回はこれを解決しました
どうやったか
解決したcommit
https://github.com/sisisin-sandbox/monorepo-tsconfig/commit/ec424adc9dfff71f4450c4ce92c30d75f1c3f67f
(このリポジトリ構成についてはこの辺参考のこと)
- それぞれの環境向けのtsconfigを用意
- また、それぞれの環境向けのfirebase.d.tsを用意
// 別名にしておかないとfirebase変数を参照したときに `firebase` パッケージのものを参照してしまう
import { firestore as adminFirestore } from 'firebase-admin';
declare module 'firebase' {
export interface MyFirestore extends adminFirestore.Firestore {}
}
import { firestore } from 'firebase';
declare module 'firebase' {
export interface MyFirestore extends firestore.Firestore {}
}
- Repositoryは上記で作成した
MyFirestore
型を使って型付けする
import { MyFirestore } from 'firebase';
export class HogeRepository {
constructor(private db: MyFirestore) {}
// 以下略
- それぞれの環境向けのtsconfigで、
include
に上記型定義ファイルを含めるようにする
概ね以上になります
つまりどういうこと?
何が問題だったかと言うと、型がnode/browser環境下でそれぞれ違うということなので、それぞれの環境用にトランスパイル出来るようにしつつ、型をトランスパイル時に差し替えということをやりました
つまりトランスパイル時に型についてDependency Injectionしたことになりますね!
この構成だと、front,sharedという2つのパッケージをブラウザ向けにトランスパイルしたいので front/tsconfig.json
及び shared/tsconfig.browser.json
は include
にブラウザ向けfirebase.d.tsを含めるようにして解決。
functionsも同様、といった具合です
そもそもfirebaseの型定義がuniversalを意識して書かれていればこんなことにはならないんですが、まあしょうがないということで。
あまり起こる事象ではないでしょうが、複数環境向けのリポジトリで同様の課題にあたったときに同じアプローチで解決出来ると思います
次回は資料のもう一つの心残り、 functionsから shared/lib/esのimportがあったとき(またはその逆)にトランスパイルエラーにならない
をpaths使って解決する編になる気がします(やる気があれば)