diff --git a/src/index.d.ts b/src/index.d.ts index 552e252..4bb5cf4 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -37,7 +37,7 @@ declare class DataLoader { * ]); * */ - loadMany(keys: K[]): Promise; + loadMany(keys: ArrayLike): Promise; /** * Clears the value at `key` from the cache, if it exists. Returns itself for @@ -70,7 +70,8 @@ declare namespace DataLoader { // A Function, which when given an Array of keys, returns a Promise of an Array // of values or Errors. - export type BatchLoadFn = (keys: K[]) => PromiseLike>; + export type BatchLoadFn = + (keys: ArrayLike) => PromiseLike>; // Optionally turn off batching or caching or provide a cache key function or a // custom cache instance. diff --git a/src/index.js b/src/index.js index 4bcaff9..379073e 100644 --- a/src/index.js +++ b/src/index.js @@ -129,13 +129,18 @@ class DataLoader { * */ loadMany(keys: $ReadOnlyArray): Promise> { - if (!Array.isArray(keys)) { + if (!isArrayLike(keys)) { throw new TypeError( 'The loader.loadMany() function must be called with Array ' + - `but got: ${keys}.` + `but got: ${(keys: any)}.` ); } - return Promise.all(keys.map(key => this.load(key))); + // Support ArrayLike by using only minimal property access + const loadPromises = []; + for (let i = 0; i < keys.length; i++) { + loadPromises.push(this.load(keys[i])); + } + return Promise.all(loadPromises); } /** @@ -266,7 +271,7 @@ function dispatchQueueBatch( batchPromise.then(values => { // Assert the expected resolution from batchLoadFn. - if (!Array.isArray(values)) { + if (!isArrayLike(values)) { throw new TypeError( 'DataLoader must be constructed with a function which accepts ' + 'Array and returns Promise>, but the function did ' + @@ -345,4 +350,15 @@ type LoaderQueue = Array<{ reject: (error: Error) => void; }>; +// Private +function isArrayLike(x: mixed): boolean { + return ( + typeof x === 'object' && + x !== null && + typeof x.length === 'number' && + (x.length === 0 || + (x.length > 0 && Object.prototype.hasOwnProperty.call(x, x.length - 1))) + ); +} + module.exports = DataLoader;