flow icon indicating copy to clipboard operation
flow copied to clipboard

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

Open lll000111 opened this issue 9 years ago • 6 comments

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.

lll000111 avatar Feb 02 '17 08:02 lll000111

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.

julienw avatar Jun 12 '17 08:06 julienw

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).

lll000111 avatar Aug 18 '17 08:08 lll000111

I ended up rewriting all of it, see https://github.com/devtools-html/perf.html/blob/8436a874983faf0690b3dbba82d094859541ed76/src/types/indexeddb.js

julienw avatar Aug 18 '17 08:08 julienw

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

lll000111 avatar Aug 18 '17 10:08 lll000111

This worked for me stackoverflow

Christiantyemele avatar Mar 25 '24 15:03 Christiantyemele

Just found out that we can wrap event.target with a proper request type:

const db = (event.target as IDBOpenDBRequest).result;
// or
(event.target as IDBRequest).result

muratgozel avatar Jul 10 '24 21:07 muratgozel