Reputation: 9673
My apologies for the bad title, I don't know how to better describe this :)
I'm using Flow in an application based on an IndexedDB database with auto-incrementing IDs. So basically, I create some objects (with no id
property), write them to the database (at which point they are given an id
property by IndexedDB), and then read them back out (any object read from the DB is guaranteed to have a numeric id
property).
I have some functions that operate on these objects. Sometimes they only operate on objects with IDs, sometimes they only operate on objects without IDs, and sometimes they operate on both. It's the latter case that is trickiest. Here's one attempt, using two different types for the objects before and after being written to the DB (so, without and with the id
property, respectively):
/* @flow */
type BeforeDb = {prop: string};
type AfterDb = BeforeDb & {id: number};
var beforeDb: BeforeDb = {prop: 'hi'};
var afterDb: AfterDb = {id: 1, prop: 'hi'};
function a(obj: BeforeDb | AfterDb): BeforeDb | AfterDb {
if (typeof obj.id === 'number') {
console.log(obj.id * 2);
}
return obj;
}
function b(obj: AfterDb) {}
var x = a(afterDb);
b(x);
That produces an error on the last line, because it doesn't know that x
is of type AfterDb
, and I'm not sure how to convey that information appropriately.
Another idea would be to use bounded polymorphisms, except I don't believe this can create something like my a
function above because it can't handle the fact that id
is sometimes undefined. Like I want to do something like this:
function a<T: {id?: number}>(obj: T): T {
if (typeof obj.id === 'number') {
console.log(obj.id * 2);
}
return obj;
}
but that doesn't work. If I assigned a dummy value to id
so it was always numeric (like -1 instead of undefined) then this would work, but then I'd have to be very careful about remembering to delete the id
before the first write to the DB so the real id
could be auto-generated, which would be pretty ugly.
After that, I'm pretty much out of good ideas. The one thing I got to work was to use just one type, like:
type Obj = {id?: number, prop: string};
and then explicitly check if the id
property is there or not in every function that uses the id
property. But that's annoying, because I have a bunch of functions that are only called with the output of IndexedDB, so I already know id
is guaranteed to be there. I just don't know how to tell Flow that.
Any ideas?
Upvotes: 2
Views: 140
Reputation: 1462
function a<T: BeforeDb | AfterDb>(obj: T): T {
if (typeof obj.id === 'number') {
console.log(obj.id * 2);
}
return obj;
}
Upvotes: 5