Let me try to explain the situation:
add
method from collection
withConverter
bdw.. I'm using Mobx-state-tree
Let me describe step by step
Company model defined by mobx-state-tree
const CompanyModel = types.model({
id: types.identifier,
name: types.string
});
Types that I will needed
After I call add
method, CompanyReference is that what I get from firestore
type CompanyReference = firebase.firestore.DocumentReference<
Instance<typeof CompanyModel>
>;
TCompanySnapshot is that what I'm sending to the firestore by using add
method
type TCompanySnapshot = Omit<SnapshotIn<typeof CompanyModel>, "id">;
Converting from and to firestore by using withCOnverter
TCompanySnapshot
objectCompanyModel
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
});
}
};
Now, when I tried to create method that create new company, I'm getting typing error
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
You can check this error on code sandbox
https://codesandbox.io/s/firebase-typescript-mobx-state-tree-n9s7o?file=/src/index.ts
The issue you are getting is caused by your use of withConverter()
, which is changing the type of the CollectionReference
so that it doesn't match your CompanyReference
.
See Firestore#collection()
, CollectionReference#withConverter()
and CollectionReference#add()
:
firestore
.collection("companies") // CollectionReference<DocumentData>
.withConverter<TCompanySnapshot>(createCompanyConverter) // CollectionReference<TCompanySnapshot>
.add(companyData); // Promise<DocumentReference<TCompanySnapshot>>
Note that DocumentReference<TCompanySnapshot> !== DocumentReference<Instance<typeof CompanyModel>>
.
If you are happy with how your object is being converted, you could forcibly override the type using the following line:
return added as Promise<CompanyReference>;
However, you should instead correct your FirestoreDataConverter
instance. There is also no need to explicitly over-type everything as just specifying firebase.firestore.FirestoreDataConverter<Instance<typeof CompanyModel>>
as the result's type should spread the appropriate types to the other objects.
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
});
}
};