Typescript封装Firebase Firestore通用withConverter出现类型错误如何解决
解决方案
核心调整逻辑
首先新增通用类型约束,明确所有使用该转换器的领域类必须实现toFirestoreJSON方法,同时修正构造函数的类型定义,对齐业务类的入参规则。
第一步:定义通用基础类型和转换器
import { CollectionReference, DocumentReference, QueryDocumentSnapshot, SnapshotOptions, DocumentData } from "firebase/firestore" // 所有需要使用通用转换器的领域类必须实现该接口 interface FirestoreConvertible<D> { toFirestoreJSON: () => Partial<D> } // 领域类构造函数类型定义,对齐你现有业务类的构造入参规则 type DomainConstructor<T, D> = new (props: Partial<D> & { id?: string; itemID?: string }) => T /** * 通用 Collection 转换器封装 */ export function collectionWithConverter<T extends FirestoreConvertible<D>, D>( TCreator: DomainConstructor<T, D>, ref: CollectionReference<DocumentData> ): CollectionReference<T> { return ref.withConverter<T>({ toFirestore: (obj: T) => { return obj.toFirestoreJSON() as DocumentData }, fromFirestore: (snapshot: QueryDocumentSnapshot, options: SnapshotOptions) => { const data = snapshot.data(options) as D // 对齐原有非通用实现逻辑,自动注入id和itemID return new TCreator({ ...data, id: snapshot.id, itemID: snapshot.id }) } }) } /** * 通用 Document 转换器封装 */ export function documentWithConverter<T extends FirestoreConvertible<D>, D>( TCreator: DomainConstructor<T, D>, ref: DocumentReference<DocumentData> ): DocumentReference<T> { return ref.withConverter<T>({ toFirestore: (obj: T) => { return obj.toFirestoreJSON() as DocumentData }, fromFirestore: (snapshot: QueryDocumentSnapshot, options: SnapshotOptions) => { const data = snapshot.data(options) as D return new TCreator({ ...data, id: snapshot.id, itemID: snapshot.id }) } }) }
第二步:调整公共获取引用的方法
export function getCollectionReference<T extends FirestoreConvertible<D>, D>( collectionName: Collections, TCreator: DomainConstructor<T, D> ): CollectionReference<T> { return collectionWithConverter(TCreator, firestoreAccessor(collectionName)) } export function getDocumentReference<T extends FirestoreConvertible<D>, D>( collectionName: Collections, itemID: string, TCreator: DomainConstructor<T, D> ): DocumentReference<T> { return documentWithConverter(TCreator, doc(getFirestore(), collectionName, itemID)) }
第三步:业务调用示例
不需要为每个领域类单独写转换器,直接传入类构造函数即可,原有Item类无需任何修改:
export async function getItem(itemID: string): Promise<Item | null> { // 传入Item构造函数和对应的Props类型即可 const ref = getDocumentReference<Item, ItemProps>(Collections.ITEMS, itemID, Item) const snap = await getDoc(ref) if (snap.exists()) { return snap.data() } return null }
原有报错修复说明
- 报错1 'data' is declared but its value is never read:修正后TS可正确识别
data在构造函数参数中的展开使用,不会再误报未使用 - 报错2/3 类型不匹配:手动为
withConverter指定泛型T,同时将toFirestore返回值显式断言为DocumentData,对齐Firestore接口要求 - 报错4 'T' could be instantiated with an arbitrary type:通过
T extends FirestoreConvertible<D>约束泛型范围,明确T必须实现toFirestoreJSON方法,避免无意义的类型传入 - 构造函数类型不兼容:将原泛型中无入参的构造函数定义,修改为接收
Partial<D>和id、itemID参数的类型,和实际业务类构造逻辑对齐
内容的提问来源于stack exchange,提问作者user2561417
相关产品推荐
相关产品推荐

