Skip to content

Commit 8808057

Browse files
authored
[TS] Support ArrayLike in batch function and loadMany (#214)
* Use ReadonlyArray instead of Array on input args The runtime code does not alter the Arrays in question, and it is good form to prefer `ReadonlyArray<T>` over `Array<T>` (aka `T[]`) in the input position when one can. * Use ReadonlyArray in promise result * Support ArrayLike
1 parent 80396ee commit 8808057

File tree

2 files changed

+23
-6
lines changed

2 files changed

+23
-6
lines changed

src/index.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ declare class DataLoader<K, V, C = K> {
3737
* ]);
3838
*
3939
*/
40-
loadMany(keys: K[]): Promise<V[]>;
40+
loadMany(keys: ArrayLike<K>): Promise<V[]>;
4141

4242
/**
4343
* Clears the value at `key` from the cache, if it exists. Returns itself for
@@ -70,7 +70,8 @@ declare namespace DataLoader {
7070

7171
// A Function, which when given an Array of keys, returns a Promise of an Array
7272
// of values or Errors.
73-
export type BatchLoadFn<K, V> = (keys: K[]) => PromiseLike<Array<V | Error>>;
73+
export type BatchLoadFn<K, V> =
74+
(keys: ArrayLike<K>) => PromiseLike<ArrayLike<V | Error>>;
7475

7576
// Optionally turn off batching or caching or provide a cache key function or a
7677
// custom cache instance.

src/index.js

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,18 @@ class DataLoader<K, V, C = K> {
129129
*
130130
*/
131131
loadMany(keys: $ReadOnlyArray<K>): Promise<Array<V>> {
132-
if (!Array.isArray(keys)) {
132+
if (!isArrayLike(keys)) {
133133
throw new TypeError(
134134
'The loader.loadMany() function must be called with Array<key> ' +
135-
`but got: ${keys}.`
135+
`but got: ${(keys: any)}.`
136136
);
137137
}
138-
return Promise.all(keys.map(key => this.load(key)));
138+
// Support ArrayLike by using only minimal property access
139+
const loadPromises = [];
140+
for (let i = 0; i < keys.length; i++) {
141+
loadPromises.push(this.load(keys[i]));
142+
}
143+
return Promise.all(loadPromises);
139144
}
140145

141146
/**
@@ -266,7 +271,7 @@ function dispatchQueueBatch<K, V>(
266271
batchPromise.then(values => {
267272

268273
// Assert the expected resolution from batchLoadFn.
269-
if (!Array.isArray(values)) {
274+
if (!isArrayLike(values)) {
270275
throw new TypeError(
271276
'DataLoader must be constructed with a function which accepts ' +
272277
'Array<key> and returns Promise<Array<value>>, but the function did ' +
@@ -345,4 +350,15 @@ type LoaderQueue<K, V> = Array<{
345350
reject: (error: Error) => void;
346351
}>;
347352

353+
// Private
354+
function isArrayLike(x: mixed): boolean {
355+
return (
356+
typeof x === 'object' &&
357+
x !== null &&
358+
typeof x.length === 'number' &&
359+
(x.length === 0 ||
360+
(x.length > 0 && Object.prototype.hasOwnProperty.call(x, x.length - 1)))
361+
);
362+
}
363+
348364
module.exports = DataLoader;

0 commit comments

Comments
 (0)