Firebase + Typescript - ID 属性 和 withConverter 问题(创建没有 ID 属性 的新文档)
Firebase + Typescript - issue with ID property and withConverter (creating an new Document that don't have ID property)
让我试着解释一下情况:
- 为了在 firestore 中创建新文档,我使用了
collection
中的 add
方法
- 为了保证类型安全,使用 typescript,我使用
withConverter
- 当我创建新文档时,我的对象上没有 ID 属性
- 创建对象后,我有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 相互转换
- 将数据发送到 firestore,只需使用常规
TCompanySnapshot
对象
- 从 firestore 接收一些对象(现在我有 ID 属性),转换成
CompanyModel
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
});
}
};
让我试着解释一下情况:
- 为了在 firestore 中创建新文档,我使用了
collection
中的 - 为了保证类型安全,使用 typescript,我使用
withConverter
- 当我创建新文档时,我的对象上没有 ID 属性
- 创建对象后,我有ID属性
add
方法
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
方法
type TCompanySnapshot = Omit<SnapshotIn<typeof CompanyModel>, "id">;
使用 withCOnverter
- 将数据发送到 firestore,只需使用常规
TCompanySnapshot
对象 - 从 firestore 接收一些对象(现在我有 ID 属性),转换成
CompanyModel
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
});
}
};