main
js 61 lines 1.76 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10 import isArray from 'shared/isArray';
11
12 /**
13 * Accumulates items that must not be null or undefined into the first one. This
14 * is used to conserve memory by avoiding array allocations, and thus sacrifices
15 * API cleanness. Since `current` can be null before being passed in and not
16 * null after this function, make sure to assign it back to `current`:
17 *
18 * `a = accumulateInto(a, b);`
19 *
20 * This API should be sparingly used. Try `accumulate` for something cleaner.
21 *
22 * @return {*|array<*>} An accumulation of items.
23 */
24
25 function accumulateInto<T>(
26 current: ?(Array<T> | T),
27 next: T | Array<T>,
28 ): T | Array<T> {
29 if (next == null) {
30 throw new Error('Accumulated items must not be null or undefined.');
31 }
32
33 if (current == null) {
34 return next;
35 }
36
37 // Both are not empty. Warning: Never call x.concat(y) when you are not
38 // certain that x is an Array (x could be a string with concat method).
39 if (isArray(current)) {
40 if (isArray(next)) {
41 // $FlowFixMe[incompatible-use] `isArray` does not ensure array is mutable
42 // $FlowFixMe[method-unbinding]
43 current.push.apply(current, next);
44 return current;
45 }
46 // $FlowFixMe[incompatible-use] `isArray` does not ensure array is mutable
47 current.push(next);
48 return current;
49 }
50
51 if (isArray(next)) {
52 // A bit too dangerous to mutate `next`.
53 /* $FlowFixMe[incompatible-return] unsound if `next` is `T` and `T` an array,
54 * `isArray` might refine to the array element type of `T` */
55 return [current].concat(next);
56 }
57
58 return [current, next];
59 }
60
61 export default accumulateInto;