Reputation: 23261
In my Typescript application code I define a model which uses a timestamp generated on the server by Firestore. When the document returns from the database this field will be an ISO string. I want to use the same model definition throughout my app for both writing and reading data, but this poses a problem.
I would typically write something like this:
interface Document {
title: string,
createdAt: string
}
async function addDocument(document: Document): Promise<string> {
const id = await firestore.collection('documents').add(someDocument)
return id
}
async function getDocumentData(documentId: string): Promise<Document> {
const doc = await firestore.collection('documents').doc(documentId).get()
invariant(doc.exists, `No document available with id ${documentId}`)
return doc.data() as Document
}
const someDocument: Document = {
title: "How to",
createdAt: firestore.FieldValue.serverTimestamp()
}
const newDocumentId = await addDocument(someDocument)
Now the Typescript compiler is complaining that the value for someDocument
is not compatible, because createdAt
is defined as a string.
Before, I hacked around this by tricking the compiler into believing it is a string with createdAt: firestore.FieldValue.serverTimestamp() as string
.
With a recent update to Typescript this tolerance seems to have disappeared with the strict settings that I'm using. The compiler is now telling me:
Type 'FieldValue' cannot be converted to type 'string'.
In stead of working around the compiler again, I'm wondering what would be the correct way to handle this?
-- edit --
Looking at this again because of the upcoming change in Firestore timestamp behaviour I discovered that the API didn't actually return ISO strings but Date object. Because Date objects have automatic string conversion my code always worked, but the type definitions were incorrect in that sense. This doesn't change much to my initial question though.
Upvotes: 4
Views: 3423
Reputation: 23261
The new behavior for Firebase will be to return the Timestamp
object from the db methods, instead of a Date object.
In my type definitions file I now import the Timestamp type (you need Typescript 2.9 for this) and then use it in my models like this:
export type FirestoreTimestamp = import("firebase").firestore.Timestamp;
export interface LockableItem {
isLocked: boolean;
lockedBy?: UserId;
lockedAt?: FirestoreTimestamp;
}
When setting the lockedAt field with a FieldValue you can now simply do this:
const item: LockableItem = {
isLocked: true,
lockedAt: FieldValue.serverTimestamp() as FirestoreTimestamp,
lockedBy: "someuser"
}
Upvotes: 8