Open iamuzo opened 4 years ago
Looks like this is the same error as https://github.com/firebase/firebase-functions/issues/404. It's a really long and messy thread, so you don't have to read the whole thing, but the cause of the error is you're running a different version of typescript than the one that Functions expects.
Can you share the versions in your package.json
file?
@morganchen12 : I resolved my issue using 3 steps:
I updated my package.json file to use firebase-admin version 8.0.0 and above. My package.json file currently looks like this:
{
"name": "functions",
"scripts": {
"lint": "./node_modules/.bin/tslint -p tslint.json",
"build": "./node_modules/.bin/tsc",
"serve": "npm run build && firebase serve --only functions",
"shell": "npm run build && firebase experimental:functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"main": "lib/index.js",
"dependencies": {
"firebase-admin": "^8.0.0",
"firebase-functions": "^3.3.0"
},
"devDependencies": {
"tslint": "^5.20.0",
"typescript": "^2.9.2"
},
"private": true,
"engines": {
"node": "8"
}
}
Added the additional step of running npm run build
as suggested in firebase/firestore-codelab-extended-swift/issues/27
After this change, running firebase deploy
resulted in new error messages:
src/index.ts:27:20 - error TS2532: Object is possibly 'undefined'.
27 const rating = eventData.rating;
~~~~~~~~~
src/index.ts:32:28 - error TS2532: Object is possibly 'undefined'.
32 const prevRating = previousValue.rating;
~~~~~~~~~~~~~
src/index.ts:39:26 - error TS2532: Object is possibly 'undefined'.
39 const restaurantID = eventData.restaurantID;
~~~~~~~~~
src/index.ts:44:27 - error TS2532: Object is possibly 'undefined'.
44 const difference = previousValue.rating - rating
~~~~~~~~~~~~~
src/index.ts:61:21 - error TS2532: Object is possibly 'undefined'.
61 const oldRating = restaurantDoc.data().averageRating;
~~~~~~~~~~~~~~~~~~~~
src/index.ts:62:25 - error TS2532: Object is possibly 'undefined'.
62 const oldNumReviews = restaurantDoc.data().reviewCount;
~~~~~~~~~~~~~~~~~~~~
which suggested either a mistype on my end or a change in how typescript evaluates code.
This stackoverflow question helped me figure out what to do. Thus the new contents of my index.ts file are:
// Copyright (c) 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
type Firestore = admin.firestore.Firestore;
const app = admin.initializeApp();
export const computeAverageReview = functions.firestore
.document('reviews/{reviewId}').onWrite((change, context) => {
const eventData = change.after!.data();
const prev = change.before;
const rating = eventData!.rating;
let previousValue
if (prev.exists) {
previousValue = prev.data();
const prevRating = previousValue?.rating;
if (rating === prevRating) {
console.log("not a new rating.");
return null;
}
}
const restaurantID = eventData!.restaurantID;
const db = app.firestore()
if (prev.exists) {
const difference = previousValue?.rating - rating
return updateAverage(db, restaurantID, difference, true);
} else {
return updateAverage(db, restaurantID, rating, false);
}
});
async function updateAverage(db: Firestore, restaurantID: string, newRating: number, prev: boolean) {
const updateDB = db.collection('restaurants').doc(restaurantID);
const restaurantDoc = await updateDB.get();
if (!restaurantDoc.exists) {
console.log("Document does not exist!");
return null;
}
const oldRating = restaurantDoc?.data()?.averageRating;
const oldNumReviews = restaurantDoc?.data()?.reviewCount;
let newNumReviews = oldNumReviews+1;
let newAvgRating = ((oldRating*oldNumReviews)+newRating)/newNumReviews;
if (prev) {
newNumReviews = oldNumReviews;
newAvgRating = ((oldRating*oldNumReviews)-newRating)/oldNumReviews;
}
await updateDB.update({averageRating: newAvgRating, reviewCount: newNumReviews});
console.log("average updated");
return null;
}
/**
* TODO(DEVELOPER): Write the updateRest Function here.
*/
/**
*TODO(DEVELOPER): Add updateRestaurant helper function here.
*/
Let me know what you think. Thanks
PS: the force unwrapping of the values makes me nervous. Is this the recommended way to do this? I could leave things like this for now till I wrap up the workshop and then look further into Typescript BUT if you have any insights that would be greatly appreciated as it would speed up my learning. Thanks
Thanks for investigating, looks like the Typescript in the codelab needs to be updated.
The unwrapping is not the best way to do this, because it creates a tight coupling between your server function and the client. For example, in the review update handler, this line:
const eventData = change.after!.data();
will break if you ever add a feature to delete reviews to the app, since after
will be undefined
. In a complex, long-lived, and frequently-updated app, you will inevitably have users who choose to remain on older versions instead of upgrading their apps, so it's good to not tightly couple your functions to an app version's implementation because that inflexibility will cost you in the future.
Functions makes this easier since deploying is pretty easy and the functions themselves are stateless. So you could just add the force-unwraps as they are now and then just change them when you want to update your app. In the case of a few force-unwraps, this is only viable because removing the unwraps and handling the error case is easy.
I am getting this same error. I went through and updated my dependencies in my package.json, but that didn't work.
@C2SO can you file a new issue with your compiler/linter error?
No solution to this yet?
same problem !!
Same problem, appeared out of nowhere.. Haven't changed a bit in the code.
Same problem
Try running "firebase init hosting" before the deploy command
Device: MacBook Pro
Operating system version: macOS Catalina (version 10.15.1)
Swift version:
Apple Swift version 5.1.2 (swiftlang-1100.0.278 clang-1100.0.33.9) Target: x86_64-apple-darwin19.0.0
Node Version:
node v12.14.0 (npm v6.13.4)
Firebase --version
7.10.0
What steps will reproduce the problem:
What is the expected result?
firebase deploy
should result in success with terminal output ofDeploy complete!
What happens instead of that?
running
firebase deploy
results in error with terminal output:Contents of debug.log