Currently cleaning up a bit of code and rewritting a lot in typescript. What I found what made me curious is the following code:
const userRef = firestore.collection('users').doc(userId);
const userDoc = await userRef.get();
if (userDoc.exists) {
const userData = userDoc.data();
const currentUserBalance = userData.balance ? userData.balance : 0;
}
Now Typescript will plain that userData
is possibily undefined
, but the Documents .data()
cannot be undefined when I check for the document existing above in my if
block. Just curious on why that happens and if I have a logic issue here or not.
Currently cleaning up a bit of code and rewritting a lot in typescript. What I found what made me curious is the following code:
const userRef = firestore.collection('users').doc(userId);
const userDoc = await userRef.get();
if (userDoc.exists) {
const userData = userDoc.data();
const currentUserBalance = userData.balance ? userData.balance : 0;
}
Now Typescript will plain that userData
is possibily undefined
, but the Documents .data()
cannot be undefined when I check for the document existing above in my if
block. Just curious on why that happens and if I have a logic issue here or not.
- If the provided answer was helpful for you, please mark it as correct. – Doug Stevenson Commented Aug 31, 2019 at 20:44
2 Answers
Reset to default 6TypeScript doesn't have any knowledge of the relationship between exists
and data()
. It just knows the signature of data()
says that the return value can be DocumentSnapshot or undefined. So, you must satisfy the piler by either:
- First checking for "truthiness", then use the results if so:
const data = userDoc.data()
if (data) {
// In this block, data is now typed as just DocumentData,
// undefined is no longer an option.
}
- Telling TypeScript that you know for sure that the results will be "truthy" by using the
!
operator:
const data = userDoc.data()! // data is now typed as just DocumentData
Unfortunately, even though Firestore adapters both for Node.js and the web are written mainly in TypeScript, they aren't designed for the language.
To solve the problem, I wrote Typesaurus, TypeScript-first ORM (or ODM if you wish) that solves this problem:
import { get, collection } from './src'
type User = { name: string }
const users = collection<User>('users')
async function main() {
const user = await get(users, 'qwe') // get will return document or undefined
if (user) {
console.log(user.data.name) // user is Doc<User>
} else {
// user is undefined
}
}
main()