Firebase + Typescript - ID 属性 和 withConverter 问题(创建没有 ID 属性 的新文档)

Firebase + Typescript - issue with ID property and withConverter (creating an new Document that don't have ID property)

让我试着解释一下情况:

  1. 为了在 firestore 中创建新文档,我使用了 collection
  2. 中的 add 方法
  3. 为了保证类型安全,使用 typescript,我使用 withConverter
  4. 当我创建新文档时,我的对象上没有 ID 属性
  5. 创建对象后,我有ID属性

bdw.. I'm using Mobx-state-tree

密码

让我一步一步描述

mobx-state-tree定义的公司模型

const CompanyModel = types.model({
  id: types.identifier,
  name: types.string
});

我需要的类型

在我调用 add 方法后,CompanyReference 就是我从 firestore

得到的
type CompanyReference = firebase.firestore.DocumentReference<
  Instance<typeof CompanyModel>
>;

TCompanySnapshot 是我使用 add 方法

发送到 firestore 的内容
type TCompanySnapshot = Omit<SnapshotIn<typeof CompanyModel>, "id">;

使用 withCOnverter

与 Firestore 相互转换
const createCompanyConverter: firebase.firestore.FirestoreDataConverter<Instance<
  typeof CompanyModel
>> = {
  toFirestore(modelObject: TCompanySnapshot): firebase.firestore.DocumentData {
    return modelObject;
  },
  fromFirestore(
    snapshot: firebase.firestore.QueryDocumentSnapshot<TCompanySnapshot>,
    options: firebase.firestore.SnapshotOptions
  ): Instance<typeof CompanyModel> {
    const data = snapshot.data(options);
    return CompanyModel.create({
      id: snapshot.id,
      ...data
    });
  }
};

问题

现在,当我尝试创建创建新公司的方法时,出现输入错误

function addCompany(
  // companyData: SnapshotIn<typeof CompanyModel>,
  companyData: TCompanySnapshot
): Promise<CompanyReference> {
  const added = firestore
    .collection("companies")
    // .withConverter<Instance<typeof CompanyModel>>(createCompanyConverter)
    .withConverter<TCompanySnapshot>(createCompanyConverter)
    .add(companyData);

  return added;   // <<<<<------ ERROR HERE
}

Property 'id' is missing in type

您可以在 code sandbox

上检查此错误

https://codesandbox.io/s/firebase-typescript-mobx-state-tree-n9s7o?file=/src/index.ts

您遇到的问题是由您使用 withConverter() 引起的,它正在更改 CollectionReference 的类型,因此它与您的 CompanyReference 不匹配。

Firestore#collection(), CollectionReference#withConverter() and CollectionReference#add():

firestore
  .collection("companies")                                 // CollectionReference<DocumentData>
  .withConverter<TCompanySnapshot>(createCompanyConverter) // CollectionReference<TCompanySnapshot>  
  .add(companyData);                                       // Promise<DocumentReference<TCompanySnapshot>>

注意 DocumentReference<TCompanySnapshot> !== DocumentReference<Instance<typeof CompanyModel>>.

如果您对对象的转换方式感到满意,可以使用以下行强制覆盖类型:

return added as Promise<CompanyReference>;

但是,您应该更正您的 FirestoreDataConverter 实例。也不需要显式地重写所有内容,只需指定 firebase.firestore.FirestoreDataConverter<Instance<typeof CompanyModel>> 因为结果的类型应该将适当的类型传播到其他对象。

const createCompanyConverter: firebase.firestore.FirestoreDataConverter<Instance<typeof CompanyModel>> = {
  toFirestore(modelObject) {
    const objToUpload = { ...modelObject } as firebase.firestore.DocumentData; // DocumentData is mutable
    delete objToUpload.id; // make sure to remove ID so it's not uploaded to the document
    return objToUpload;
  },
  fromFirestore(snapshot, options) {
    const data = snapshot.data(options); // "as Omit<Instance<typeof CompanyModel>, "id">" could be added here

    // spread data first, so an incorrectly stored id gets overridden
    return CompanyModel.create({
      ...data, 
      id: snapshot.id
    });
  }
};