You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Angular/Fire模块化API实现通用转换器?

Angular Fire 模块化API通用数据转换器类型错误解决方法

问题背景

从旧版@angular/fire compat API迁移至新模块化API时,原通用数据获取方法无法直接适配,编写的通用转换器出现类型不兼容错误,核心是QueryDocumentSnapshot类型的参数定义问题。

原Compat API代码

通用数据获取方法

get<T extends DbModel>(TCreator: new () => T, id: string, refParams: any = undefined): Observable<T | undefined> {
    let o = new TCreator();
    return this._afs.doc<T>(`${o.getRef(refParams)}/${id}`)
      .valueChanges().pipe(
        map(value => {
          return value ? { ...value, id } : value;
        })
      );
}

DbModel抽象类

export abstract class DbModel {
    [index: string]: any;
    abstract getRef(refParams: any): string;
    getGroupName(): string { throw new Error('Group name not set'); }
    id!: string;
}

模块化API中的错误实现

错误的通用转换器

private _converter = <T>() => ({
    toFirestore: (data: PartialWithFieldValue<T>) => data,
    fromFirestore: (snap: QueryDocumentSnapshot<T>) => snap.data()
})

出错的getModular方法

getModular<T extends DbModel>(TCreator: new () => T, id: string, refParams: any = undefined) : Observable<T | undefined> {
    let instance = new TCreator();
    let docRef = doc(this._afsModular, `${instance.getRef(refParams)}/${id}`)
                  .withConverter(this._converter<T>());
}

错误信息

Overload 2 of 2, '(converter: FirestoreDataConverter): DocumentReference', gave the following error.
Argument of type '{ toFirestore: (data: PartialWithFieldValue) => PartialWithFieldValue; fromFirestore: (snap: QueryDocumentSnapshot) => T; }' is not assignable to parameter of type 'FirestoreDataConverter'.
Types of property 'fromFirestore' are incompatible.
Type '(snap: QueryDocumentSnapshot) => T' is not assignable to type '(snapshot: QueryDocumentSnapshot, options?: SnapshotOptions | undefined) => T'.
Types of parameters 'snap' and 'snapshot' are incompatible.
Property 'isEqual' is missing in type 'QueryDocumentSnapshot' but required in type 'QueryDocumentSnapshot'.ts(2769)
index.d.ts(9611, 5): 'isEqual' is declared here.

解决方案

修正后的通用转换器

import { FirestoreDataConverter, PartialWithFieldValue, QueryDocumentSnapshot, SnapshotOptions } from '@angular/fire/firestore';

private _converter = <T extends DbModel>() => ({
  toFirestore: (data: PartialWithFieldValue<T>) => {
    // 移除id字段,避免将文档ID存入Firestore数据中
    const { id, ...rest } = data;
    return rest;
  },
  fromFirestore: (snapshot: QueryDocumentSnapshot, options?: SnapshotOptions) => {
    // 获取文档数据并合并ID,与原Compat API逻辑对齐
    const data = snapshot.data(options) as Omit<T, 'id'>;
    return { ...data, id: snapshot.id } as T;
  }
} as FirestoreDataConverter<T>);

修正后的getModular方法

import { doc, docData } from '@angular/fire/firestore';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

getModular<T extends DbModel>(TCreator: new () => T, id: string, refParams: any = undefined): Observable<T | undefined> {
  const instance = new TCreator();
  const docRef = doc(this._afsModular, `${instance.getRef(refParams)}/${id}`).withConverter(this._converter<T>());
  
  // 使用docData获取数据,替代原compat API的valueChanges
  return docData(docRef).pipe(
    map(doc => doc ?? undefined)
  );
}

关键说明

  1. 参数类型修正:模块化API中fromFirestore的参数是QueryDocumentSnapshot(无泛型)和可选的SnapshotOptions,而非带泛型的QueryDocumentSnapshot<T>,这是导致类型不兼容的核心原因。
  2. ID合并逻辑:原compat API会自动将文档ID合并到返回值中,模块化API需要手动在fromFirestore方法中把snapshot.id合并到数据对象里。
  3. 数据清理:toFirestore方法中移除id字段,避免将文档ID冗余存储到Firestore文档数据内。

内容的提问来源于stack exchange,提问作者Nicolas Gorga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:34:52