I would suggest starting over completely, and while the following rules may seem arbitrary and weird at first, I developed them as I was learning Rx, and they helped me avoid many pitfalls, including the one you fell into here:
- declare types for every function parameter and return type
- no
any
in following rule #1 - do not manually instantiate futures (
Observable
s orPromise
s) - nonew
anywhere in your code - any time you are going to call a function that returns a future, decide which of these three types your function is. yours here is a class C, so:
- the very first word of any class C future function should be
return
Tangentially, never use var
. Always use let
instead.
The main thing that rule #5 does is guide you towards thinking in terms of an assembly line, which is how idiomatic reactive code looks. You are trying to write in an imperative style, and while learning to let go of that instinct is hard (at least it was very hard for me), the effort is absolutely worth it.
What are the building blocks of our assembly line?
- a function that returns a Promise of a list of raw thingies
- a way to get a unique uid out of a raw thingy
- a function that takes a uid and returns a Promise of a url
- a way to cook a thingy by filling in its
photo
property with a url
What do we want?
- a single Promise of a list of cooked thingies
I don’t speak Firebase, so somebody else is going to have to cover the nuts and bolts of that syntax, but I would write the skeleton of the method like so:
interface Thingy {
uid: string;
// other stuff
photo?: string;
}
interface CookedThingy extends Thingy {
photo: string;
}
getAllCookedThingies(): Promise<CookedThingy[]> {
return this.firebase.allRawThingies()
.then((raws: Thingy[]) => {
let cooked$s = raws.map(raw => {
return this.firebase.uidToUrl(raw.uid)
.then((url) => {
raw.photo = url;
return raw as CookedThingy;
});
});
return Promise.all(cooked$s);
});
}