Flow: IndexedDB: "Property 'result' not found in EventTarget"

Created on 2 Feb 2017  路  4Comments  路  Source: facebook/flow

I used an example from the MDN pages for IndexedDB, adding some types and making only minor changes like changing the for loop to satisfy Flow, and using const:

// @flow
'use strict';

const customerData = [
    { ssn: "444-44-4444", name: "Bill", age: 35, email: "[email protected]" },
    { ssn: "555-55-5555", name: "Donna", age: 32, email: "[email protected]" }
];

const request = window.indexedDB.open('dbName', 3);

request.onupgradeneeded = function (event: Event) {

    const db = event.target.result;

    // Create another object store called "names" with the autoIncrement flag set as true.
    const objStore = db.createObjectStore("names", { autoIncrement : true });

    // Because the "names" object store has the key generator, the key for the name value is generated automatically.
    // The added records would be like:
    // key : 1 => value : "Bill"
    // key : 2 => value : "Donna"
    for (const o of customerData) {
        objStore.add(o.name);
    }
};

The problem is I get this error when I add a type to the event object in the callback, event: Event:

lib/test.js:13
 13:     const db = event.target.result;
                                 ^^^^^^ property `result`. Property not found in
 13:     const db = event.target.result;
                    ^^^^^^^^^^^^ EventTarget

Found 1 error

Looking at https://github.com/facebook/flow/blob/v0.35.0/lib/indexeddb.js there is nothing else I can use, it seems to me, no alternative type for the event.

Accepting PRs Library definitions

Most helpful comment

For events, what's usually done is typing the argument like this:
event: Event & { target: { result: IDBDatabase }}

You could also use request instead of event.target but then you'd stumble upon the issue that result is always an object store according to flow, which is obviously wrong.

All 4 comments

For events, what's usually done is typing the argument like this:
event: Event & { target: { result: IDBDatabase }}

You could also use request instead of event.target but then you'd stumble upon the issue that result is always an object store according to flow, which is obviously wrong.

Furthermore:

https://github.com/facebook/flow/blob/v0.53.1/lib/indexeddb.js#L15

declare interface IDBRequest extends EventTarget {
    result: IDBObjectStore;
    ...

The result property of a request object has the RESULT of the request (as the name implies). Which can be anything - it certainly isn't a fixed type IDBObjectStore.

Hay _anyone_ actually tried using these types? You can't even do a simple query - as soon as you try to get the result you'll run into this problem. You get the result from the request object or from the event object's target property (the request object).

Me too! You still have IDBDatabase:objectStoreNames as string[] though. This won't work, because this actually is a DOMStringList. While a DOMString indeed is string, the list is not a Javascript array. In particular DOMStringList has a method contains which does not exist on an instance of Array: Same for the item method.

So I added a definition for DOMStringList, but I leave out DOMString because for the individual strings it's okay to use string instead:

/**
 * @typedef {Object} DOMStringList
 * @property {number} length
 * @property {function(number): string} item
 * @property {function(string): boolean} contains
 */
declare interface DOMStringList {
    length: number;
    item: (number) => string | null;
    contains: (string) => boolean;
}

https://developer.mozilla.org/en/docs/Web/API/DOMStringList

Was this page helpful?
0 / 5 - 0 ratings