@samitouri / QOS-React / commits / 172e89b4bf

Reland Remove redundant initial of isArray (#21188)

* Remove redundant initial of isArray (#21163) * Reapply prettier * Type the isArray function with refinement support This ensures that an argument gets refined just like it does if isArray is used directly. I'm not sure how to express with just a direct reference so I added a function wrapper and confirmed that this does get inlined properly by closure compiler. * A few more * Rename unit test to internal This is not testing a bundle. Co-authored-by: Behnam Mohammadi <itten@live.com>

Sebastian Markbåge committed Apr 7, 2021 at 10:57 UTC 172e89b4bf0ec5ee5738af0156d90b0deef4d494
38 files changed +141 -97
packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
+6 -7
@@ -145,6 +145,8 @@ export default {
145 componentScope = currentScope;
146 }
147
148 + const isArray = Array.isArray;
149 +
150 // Next we'll define a few helpers that helps us
151 // tell if some values don't have to be declared as deps.
152
@@ -157,7 +159,7 @@ export default {
159 // ^^^ true for this reference
160 // False for everything else.
161 function isStableKnownHookValue(resolved) {
160 - if (!Array.isArray(resolved.defs)) {
162 + if (!isArray(resolved.defs)) {
163 return false;
164 }
165 const def = resolved.defs[0];
@@ -226,7 +228,7 @@ export default {
228 if (
229 id.type === 'ArrayPattern' &&
230 id.elements.length === 2 &&
229 - Array.isArray(resolved.identifiers)
231 + isArray(resolved.identifiers)
232 ) {
233 // Is second tuple value the same reference we're checking?
234 if (id.elements[1] === resolved.identifiers[0]) {
@@ -253,10 +255,7 @@ export default {
255 }
256 }
257 } else if (name === 'useTransition') {
256 - if (
257 - id.type === 'ArrayPattern' &&
258 - Array.isArray(resolved.identifiers)
259 - ) {
258 + if (id.type === 'ArrayPattern' && isArray(resolved.identifiers)) {
259 // Is first tuple value the same reference we're checking?
260 if (id.elements[0] === resolved.identifiers[0]) {
261 // Setter is stable.
@@ -270,7 +269,7 @@ export default {
269
270 // Some are just functions that don't reference anything dynamic.
271 function isFunctionWithoutCapturedValues(resolved) {
273 - if (!Array.isArray(resolved.defs)) {
272 + if (!isArray(resolved.defs)) {
273 return false;
274 }
275 const def = resolved.defs[0];
packages/jest-react/src/JestReact.js
+2 -1
@@ -8,6 +8,7 @@
8 import {REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE} from 'shared/ReactSymbols';
9
10 import invariant from 'shared/invariant';
11 +import isArray from 'shared/isArray';
12
13 function captureAssertion(fn) {
14 // Trick to use a Jest matcher inside another Jest matcher. `fn` contains an
@@ -42,7 +43,7 @@ export function unstable_toMatchRenderedOutput(root, expectedJSX) {
43 let actualJSX;
44 if (actualJSON === null || typeof actualJSON === 'string') {
45 actualJSX = actualJSON;
45 - } else if (Array.isArray(actualJSON)) {
46 + } else if (isArray(actualJSON)) {
47 if (actualJSON.length === 0) {
48 actualJSX = null;
49 } else if (actualJSON.length === 1) {
packages/react-devtools-shared/src/backend/renderer.js
+2 -1
@@ -105,6 +105,7 @@ import type {
105 ElementType,
106 } from 'react-devtools-shared/src/types';
107 import is from 'shared/objectIs';
108 +import isArray from 'shared/isArray';
109
110 type getDisplayNameForFiberType = (fiber: Fiber) => string | null;
111 type getTypeSymbolType = (type: any) => Symbol | number;
@@ -1137,7 +1138,7 @@ export function attach(
1138 memoizedState.hasOwnProperty('create') &&
1139 memoizedState.hasOwnProperty('destroy') &&
1140 memoizedState.hasOwnProperty('deps') &&
1140 - (memoizedState.deps === null || Array.isArray(memoizedState.deps)) &&
1141 + (memoizedState.deps === null || isArray(memoizedState.deps)) &&
1142 memoizedState.hasOwnProperty('next')
1143 );
1144 }
packages/react-devtools-shared/src/backend/utils.js
+6 -5
@@ -9,6 +9,7 @@
9
10 import {copy} from 'clipboard-js';
11 import {dehydrate} from '../hydration';
12 +import isArray from 'shared/isArray';
13
14 import type {DehydratedData} from 'react-devtools-shared/src/devtools/views/Components/types';
15
@@ -61,9 +62,9 @@ export function copyWithDelete(
62 index: number = 0,
63 ): Object | Array<any> {
64 const key = path[index];
64 - const updated = Array.isArray(obj) ? obj.slice() : {...obj};
65 + const updated = isArray(obj) ? obj.slice() : {...obj};
66 if (index + 1 === path.length) {
66 - if (Array.isArray(updated)) {
67 + if (isArray(updated)) {
68 updated.splice(((key: any): number), 1);
69 } else {
70 delete updated[key];
@@ -84,12 +85,12 @@ export function copyWithRename(
85 index: number = 0,
86 ): Object | Array<any> {
87 const oldKey = oldPath[index];
87 - const updated = Array.isArray(obj) ? obj.slice() : {...obj};
88 + const updated = isArray(obj) ? obj.slice() : {...obj};
89 if (index + 1 === oldPath.length) {
90 const newKey = newPath[index];
91 // $FlowFixMe number or string is fine here
92 updated[newKey] = updated[oldKey];
92 - if (Array.isArray(updated)) {
93 + if (isArray(updated)) {
94 updated.splice(((oldKey: any): number), 1);
95 } else {
96 delete updated[oldKey];
@@ -111,7 +112,7 @@ export function copyWithSet(
112 return value;
113 }
114 const key = path[index];
114 - const updated = Array.isArray(obj) ? obj.slice() : {...obj};
115 + const updated = isArray(obj) ? obj.slice() : {...obj};
116 // $FlowFixMe number or string is fine here
117 updated[key] = copyWithSet(obj[key], path, value, index + 1);
118 return updated;
packages/react-dom/src/client/ReactDOMSelect.js
+4 -3
@@ -12,6 +12,7 @@ import {getCurrentFiberOwnerNameInDevOrNull} from 'react-reconciler/src/ReactCur
12
13 import {checkControlledValueProps} from '../shared/ReactControlledValuePropTypes';
14 import {getToStringValue, toString} from './ToStringValue';
15 +import isArray from 'shared/isArray';
16
17 let didWarnValueDefaultValue;
18
@@ -45,15 +46,15 @@ function checkSelectPropTypes(props) {
46 if (props[propName] == null) {
47 continue;
48 }
48 - const isArray = Array.isArray(props[propName]);
49 - if (props.multiple && !isArray) {
49 + const propNameIsArray = isArray(props[propName]);
50 + if (props.multiple && !propNameIsArray) {
51 console.error(
52 'The `%s` prop supplied to <select> must be an array if ' +
53 '`multiple` is true.%s',
54 propName,
55 getDeclarationErrorAddendum(),
56 );
56 - } else if (!props.multiple && isArray) {
57 + } else if (!props.multiple && propNameIsArray) {
58 console.error(
59 'The `%s` prop supplied to <select> must be a scalar ' +
60 'value if `multiple` is false.%s',
packages/react-dom/src/client/ReactDOMTextarea.js
+2 -2
@@ -8,12 +8,12 @@
8 */
9
10 import invariant from 'shared/invariant';
11 +import isArray from 'shared/isArray';
12
13 import {checkControlledValueProps} from '../shared/ReactControlledValuePropTypes';
14 import {getCurrentFiberOwnerNameInDevOrNull} from 'react-reconciler/src/ReactCurrentFiber';
15 import {getToStringValue, toString} from './ToStringValue';
16 import type {ToStringValue} from './ToStringValue';
16 -
17 import {disableTextareaChildren} from 'shared/ReactFeatureFlags';
18
19 let didWarnValDefaultVal = false;
@@ -100,7 +100,7 @@ export function initWrapperState(element: Element, props: Object) {
100 defaultValue == null,
101 'If you supply `defaultValue` on a <textarea>, do not pass children.',
102 );
103 - if (Array.isArray(children)) {
103 + if (isArray(children)) {
104 invariant(
105 children.length <= 1,
106 '<textarea> can only have at most one child.',
packages/react-dom/src/server/ReactDOMServerFormatConfig.js
+1 -2
@@ -46,8 +46,7 @@ import hyphenateStyleName from '../shared/hyphenateStyleName';
46 import invariant from 'shared/invariant';
47 import hasOwnProperty from 'shared/hasOwnProperty';
48 import sanitizeURL from '../shared/sanitizeURL';
49 -
50 -const isArray = Array.isArray;
49 +import isArray from 'shared/isArray';
50
51 // Per response, global state that is not contextual to the rendering subtree.
52 export type ResponseState = {
packages/react-dom/src/server/ReactPartialRenderer.js
+6 -5
@@ -14,6 +14,7 @@ import type {ReactProvider, ReactContext} from 'shared/ReactTypes';
14
15 import * as React from 'react';
16 import invariant from 'shared/invariant';
17 +import isArray from 'shared/isArray';
18 import getComponentNameFromType from 'shared/getComponentNameFromType';
19 import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame';
20 import ReactSharedInternals from 'shared/ReactSharedInternals';
@@ -1438,7 +1439,7 @@ class ReactDOMServerRenderer {
1439 defaultValue == null,
1440 'If you supply `defaultValue` on a <textarea>, do not pass children.',
1441 );
1441 - if (Array.isArray(textareaChildren)) {
1442 + if (isArray(textareaChildren)) {
1443 invariant(
1444 textareaChildren.length <= 1,
1445 '<textarea> can only have at most one child.',
@@ -1467,14 +1468,14 @@ class ReactDOMServerRenderer {
1468 if (props[propName] == null) {
1469 continue;
1470 }
1470 - const isArray = Array.isArray(props[propName]);
1471 - if (props.multiple && !isArray) {
1471 + const propNameIsArray = isArray(props[propName]);
1472 + if (props.multiple && !propNameIsArray) {
1473 console.error(
1474 'The `%s` prop supplied to <select> must be an array if ' +
1475 '`multiple` is true.',
1476 propName,
1477 );
1477 - } else if (!props.multiple && isArray) {
1478 + } else if (!props.multiple && propNameIsArray) {
1479 console.error(
1480 'The `%s` prop supplied to <select> must be a scalar ' +
1481 'value if `multiple` is false.',
@@ -1515,7 +1516,7 @@ class ReactDOMServerRenderer {
1516 value = optionChildren;
1517 }
1518 selected = false;
1518 - if (Array.isArray(selectValue)) {
1519 + if (isArray(selectValue)) {
1520 // multiple
1521 for (let j = 0; j < selectValue.length; j++) {
1522 if ('' + selectValue[j] === value) {
packages/react-dom/src/test-utils/ReactTestUtils.js
+4 -3
@@ -24,6 +24,7 @@ import {
24 rethrowCaughtError,
25 invokeGuardedCallbackAndCatchFirstError,
26 } from 'shared/ReactErrorUtils';
27 +import isArray from 'shared/isArray';
28
29 // Keep in sync with ReactDOM.js, and ReactTestUtilsAct.js:
30 const EventInternals =
@@ -97,7 +98,7 @@ function validateClassInstance(inst, methodName) {
98 }
99 let received;
100 const stringified = '' + inst;
100 - if (Array.isArray(inst)) {
101 + if (isArray(inst)) {
102 received = 'an array';
103 } else if (inst && inst.nodeType === ELEMENT_NODE && inst.tagName) {
104 received = 'a DOM node';
@@ -197,7 +198,7 @@ function scryRenderedDOMComponentsWithClass(root, classNames) {
198 }
199 const classList = className.split(/\s+/);
200
200 - if (!Array.isArray(classNames)) {
201 + if (!isArray(classNames)) {
202 invariant(
203 classNames !== undefined,
204 'TestUtils.scryRenderedDOMComponentsWithClass expects a ' +
@@ -365,7 +366,7 @@ function executeDispatch(event, listener, inst) {
366 function executeDispatchesInOrder(event) {
367 const dispatchListeners = event._dispatchListeners;
368 const dispatchInstances = event._dispatchInstances;
368 - if (Array.isArray(dispatchListeners)) {
369 + if (isArray(dispatchListeners)) {
370 for (let i = 0; i < dispatchListeners.length; i++) {
371 if (event.isPropagationStopped()) {
372 break;
packages/react-native-renderer/src/ReactNativeAttributePayload.js
+7 -6
@@ -12,6 +12,7 @@ import {
12 deepDiffer,
13 flattenStyle,
14 } from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
15 +import isArray from 'shared/isArray';
16
17 import type {AttributeConfiguration} from './ReactNativeTypes';
18
@@ -51,7 +52,7 @@ function restoreDeletedValuesInNestedArray(
52 node: NestedNode,
53 validAttributes: AttributeConfiguration,
54 ) {
54 - if (Array.isArray(node)) {
55 + if (isArray(node)) {
56 let i = node.length;
57 while (i-- && removedKeyCount > 0) {
58 restoreDeletedValuesInNestedArray(
@@ -163,12 +164,12 @@ function diffNestedProperty(
164 return updatePayload;
165 }
166
166 - if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) {
167 + if (!isArray(prevProp) && !isArray(nextProp)) {
168 // Both are leaves, we can diff the leaves.
169 return diffProperties(updatePayload, prevProp, nextProp, validAttributes);
170 }
171
171 - if (Array.isArray(prevProp) && Array.isArray(nextProp)) {
172 + if (isArray(prevProp) && isArray(nextProp)) {
173 // Both are arrays, we can diff the arrays.
174 return diffNestedArrayProperty(
175 updatePayload,
@@ -178,7 +179,7 @@ function diffNestedProperty(
179 );
180 }
181
181 - if (Array.isArray(prevProp)) {
182 + if (isArray(prevProp)) {
183 return diffProperties(
184 updatePayload,
185 // $FlowFixMe - We know that this is always an object when the input is.
@@ -212,7 +213,7 @@ function addNestedProperty(
213 return updatePayload;
214 }
215
215 - if (!Array.isArray(nextProp)) {
216 + if (!isArray(nextProp)) {
217 // Add each property of the leaf.
218 return addProperties(updatePayload, nextProp, validAttributes);
219 }
@@ -242,7 +243,7 @@ function clearNestedProperty(
243 return updatePayload;
244 }
245
245 - if (!Array.isArray(prevProp)) {
246 + if (!isArray(prevProp)) {
247 // Add each property of the leaf.
248 return clearProperties(updatePayload, prevProp, validAttributes);
249 }
packages/react-native-renderer/src/__tests__/ReactNativeAttributePayload-test.internal.js renamed
packages/react-native-renderer/src/legacy-events/EventPluginUtils.js
+6 -5
@@ -7,6 +7,7 @@
7
8 import {invokeGuardedCallbackAndCatchFirstError} from 'shared/ReactErrorUtils';
9 import invariant from 'shared/invariant';
10 +import isArray from 'shared/isArray';
11
12 export let getFiberCurrentPropsFromNode = null;
13 export let getInstanceFromNode = null;
@@ -36,14 +37,14 @@ if (__DEV__) {
37 const dispatchListeners = event._dispatchListeners;
38 const dispatchInstances = event._dispatchInstances;
39
39 - const listenersIsArr = Array.isArray(dispatchListeners);
40 + const listenersIsArr = isArray(dispatchListeners);
41 const listenersLen = listenersIsArr
42 ? dispatchListeners.length
43 : dispatchListeners
44 ? 1
45 : 0;
46
46 - const instancesIsArr = Array.isArray(dispatchInstances);
47 + const instancesIsArr = isArray(dispatchInstances);
48 const instancesLen = instancesIsArr
49 ? dispatchInstances.length
50 : dispatchInstances
@@ -78,7 +79,7 @@ export function executeDispatchesInOrder(event) {
79 if (__DEV__) {
80 validateEventDispatches(event);
81 }
81 - if (Array.isArray(dispatchListeners)) {
82 + if (isArray(dispatchListeners)) {
83 for (let i = 0; i < dispatchListeners.length; i++) {
84 if (event.isPropagationStopped()) {
85 break;
@@ -106,7 +107,7 @@ function executeDispatchesInOrderStopAtTrueImpl(event) {
107 if (__DEV__) {
108 validateEventDispatches(event);
109 }
109 - if (Array.isArray(dispatchListeners)) {
110 + if (isArray(dispatchListeners)) {
111 for (let i = 0; i < dispatchListeners.length; i++) {
112 if (event.isPropagationStopped()) {
113 break;
@@ -150,7 +151,7 @@ export function executeDirectDispatch(event) {
151 const dispatchListener = event._dispatchListeners;
152 const dispatchInstance = event._dispatchInstances;
153 invariant(
153 - !Array.isArray(dispatchListener),
154 + !isArray(dispatchListener),
155 'executeDirectDispatch(...): Invalid `event`.',
156 );
157 event.currentTarget = dispatchListener
packages/react-native-renderer/src/legacy-events/accumulate.js
+3 -2
@@ -8,6 +8,7 @@
8 */
9
10 import invariant from 'shared/invariant';
11 +import isArray from 'shared/isArray';
12
13 /**
14 * Accumulates items that must not be null or undefined.
@@ -31,11 +32,11 @@ function accumulate<T>(
32
33 // Both are not empty. Warning: Never call x.concat(y) when you are not
34 // certain that x is an Array (x could be a string with concat method).
34 - if (Array.isArray(current)) {
35 + if (isArray(current)) {
36 return current.concat(next);
37 }
38
38 - if (Array.isArray(next)) {
39 + if (isArray(next)) {
40 return [current].concat(next);
41 }
42
packages/react-native-renderer/src/legacy-events/accumulateInto.js
+4 -3
@@ -8,6 +8,7 @@
8 */
9
10 import invariant from 'shared/invariant';
11 +import isArray from 'shared/isArray';
12
13 /**
14 * Accumulates items that must not be null or undefined into the first one. This
@@ -37,8 +38,8 @@ function accumulateInto<T>(
38
39 // Both are not empty. Warning: Never call x.concat(y) when you are not
40 // certain that x is an Array (x could be a string with concat method).
40 - if (Array.isArray(current)) {
41 - if (Array.isArray(next)) {
41 + if (isArray(current)) {
42 + if (isArray(next)) {
43 current.push.apply(current, next);
44 return current;
45 }
@@ -46,7 +47,7 @@ function accumulateInto<T>(
47 return current;
48 }
49
49 - if (Array.isArray(next)) {
50 + if (isArray(next)) {
51 // A bit too dangerous to mutate `next`.
52 return [current].concat(next);
53 }
packages/react-noop-renderer/src/createReactNoop.js
+5 -4
@@ -21,6 +21,7 @@ import type {RootTag} from 'react-reconciler/src/ReactRootTags';
21
22 import * as Scheduler from 'scheduler/unstable_mock';
23 import {REACT_FRAGMENT_TYPE, REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
24 +import isArray from 'shared/isArray';
25 import {
26 DefaultEventPriority,
27 IdleEventPriority,
@@ -604,7 +605,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
605 if (typeof child === 'string') {
606 return child;
607 }
607 - if (Array.isArray(child)) {
608 + if (isArray(child)) {
609 if (child.length === 0) {
610 return null;
611 }
@@ -618,7 +619,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
619 }
620 return children;
621 }
621 - if (Array.isArray(child.children)) {
622 + if (isArray(child.children)) {
623 // This is an instance.
624 const instance: Instance = (child: any);
625 const children = childToJSX(instance.children, instance.text);
@@ -668,7 +669,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
669 if (children === null) {
670 return null;
671 }
671 - if (Array.isArray(children)) {
672 + if (isArray(children)) {
673 return {
674 $$typeof: REACT_ELEMENT_TYPE,
675 type: REACT_FRAGMENT_TYPE,
@@ -687,7 +688,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
688 if (children === null) {
689 return null;
690 }
690 - if (Array.isArray(children)) {
691 + if (isArray(children)) {
692 return {
693 $$typeof: REACT_ELEMENT_TYPE,
694 type: REACT_FRAGMENT_TYPE,
packages/react-reconciler/src/ReactChildFiber.new.js
+1 -2
@@ -31,6 +31,7 @@ import {
31 SimpleMemoComponent,
32 } from './ReactWorkTags';
33 import invariant from 'shared/invariant';
34 +import isArray from 'shared/isArray';
35 import {
36 warnAboutStringRefs,
37 enableLazyElements,
@@ -97,8 +98,6 @@ if (__DEV__) {
98 };
99 }
100
100 -const isArray = Array.isArray;
101 -
101 function coerceRef(
102 returnFiber: Fiber,
103 current: Fiber | null,
packages/react-reconciler/src/ReactChildFiber.old.js
+1 -2
@@ -31,6 +31,7 @@ import {
31 SimpleMemoComponent,
32 } from './ReactWorkTags';
33 import invariant from 'shared/invariant';
34 +import isArray from 'shared/isArray';
35 import {
36 warnAboutStringRefs,
37 enableLazyElements,
@@ -97,8 +98,6 @@ if (__DEV__) {
98 };
99 }
100
100 -const isArray = Array.isArray;
101 -
101 function coerceRef(
102 returnFiber: Fiber,
103 current: Fiber | null,
packages/react-reconciler/src/ReactFiberBeginWork.new.js
+6 -5
@@ -87,6 +87,7 @@ import {
87 enableSuspenseLayoutEffectSemantics,
88 } from 'shared/ReactFeatureFlags';
89 import invariant from 'shared/invariant';
90 +import isArray from 'shared/isArray';
91 import shallowEqual from 'shared/shallowEqual';
92 import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
93 import getComponentNameFromType from 'shared/getComponentNameFromType';
@@ -2713,11 +2714,11 @@ function validateTailOptions(
2714
2715 function validateSuspenseListNestedChild(childSlot: mixed, index: number) {
2716 if (__DEV__) {
2716 - const isArray = Array.isArray(childSlot);
2717 + const isAnArray = isArray(childSlot);
2718 const isIterable =
2718 - !isArray && typeof getIteratorFn(childSlot) === 'function';
2719 - if (isArray || isIterable) {
2720 - const type = isArray ? 'array' : 'iterable';
2719 + !isAnArray && typeof getIteratorFn(childSlot) === 'function';
2720 + if (isAnArray || isIterable) {
2721 + const type = isAnArray ? 'array' : 'iterable';
2722 console.error(
2723 'A nested %s was passed to row #%s in <SuspenseList />. Wrap it in ' +
2724 'an additional SuspenseList to configure its revealOrder: ' +
@@ -2745,7 +2746,7 @@ function validateSuspenseListChildren(
2746 children !== null &&
2747 children !== false
2748 ) {
2748 - if (Array.isArray(children)) {
2749 + if (isArray(children)) {
2750 for (let i = 0; i < children.length; i++) {
2751 if (!validateSuspenseListNestedChild(children[i], i)) {
2752 return;
packages/react-reconciler/src/ReactFiberBeginWork.old.js
+6 -5
@@ -87,6 +87,7 @@ import {
87 enableSuspenseLayoutEffectSemantics,
88 } from 'shared/ReactFeatureFlags';
89 import invariant from 'shared/invariant';
90 +import isArray from 'shared/isArray';
91 import shallowEqual from 'shared/shallowEqual';
92 import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
93 import getComponentNameFromType from 'shared/getComponentNameFromType';
@@ -2713,11 +2714,11 @@ function validateTailOptions(
2714
2715 function validateSuspenseListNestedChild(childSlot: mixed, index: number) {
2716 if (__DEV__) {
2716 - const isArray = Array.isArray(childSlot);
2717 + const isAnArray = isArray(childSlot);
2718 const isIterable =
2718 - !isArray && typeof getIteratorFn(childSlot) === 'function';
2719 - if (isArray || isIterable) {
2720 - const type = isArray ? 'array' : 'iterable';
2719 + !isAnArray && typeof getIteratorFn(childSlot) === 'function';
2720 + if (isAnArray || isIterable) {
2721 + const type = isAnArray ? 'array' : 'iterable';
2722 console.error(
2723 'A nested %s was passed to row #%s in <SuspenseList />. Wrap it in ' +
2724 'an additional SuspenseList to configure its revealOrder: ' +
@@ -2745,7 +2746,7 @@ function validateSuspenseListChildren(
2746 children !== null &&
2747 children !== false
2748 ) {
2748 - if (Array.isArray(children)) {
2749 + if (isArray(children)) {
2750 for (let i = 0; i < children.length; i++) {
2751 if (!validateSuspenseListNestedChild(children[i], i)) {
2752 return;
packages/react-reconciler/src/ReactFiberClassComponent.new.js
+1 -1
@@ -36,6 +36,7 @@ import shallowEqual from 'shared/shallowEqual';
36 import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
37 import getComponentNameFromType from 'shared/getComponentNameFromType';
38 import invariant from 'shared/invariant';
39 +import isArray from 'shared/isArray';
40 import {REACT_CONTEXT_TYPE, REACT_PROVIDER_TYPE} from 'shared/ReactSymbols';
41
42 import {resolveDefaultProps} from './ReactFiberLazyComponent.new';
@@ -81,7 +82,6 @@ import {
82 } from './SchedulingProfiler';
83
84 const fakeInternalInstance = {};
84 -const isArray = Array.isArray;
85
86 // React.Component uses a shared frozen object by default.
87 // We'll use it to determine whether we need to initialize legacy refs.
packages/react-reconciler/src/ReactFiberClassComponent.old.js
+1 -1
@@ -36,6 +36,7 @@ import shallowEqual from 'shared/shallowEqual';
36 import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
37 import getComponentNameFromType from 'shared/getComponentNameFromType';
38 import invariant from 'shared/invariant';
39 +import isArray from 'shared/isArray';
40 import {REACT_CONTEXT_TYPE, REACT_PROVIDER_TYPE} from 'shared/ReactSymbols';
41
42 import {resolveDefaultProps} from './ReactFiberLazyComponent.old';
@@ -81,7 +82,6 @@ import {
82 } from './SchedulingProfiler';
83
84 const fakeInternalInstance = {};
84 -const isArray = Array.isArray;
85
86 // React.Component uses a shared frozen object by default.
87 // We'll use it to determine whether we need to initialize legacy refs.
packages/react-reconciler/src/ReactFiberHooks.new.js
+2 -1
@@ -87,6 +87,7 @@ import {
87 import invariant from 'shared/invariant';
88 import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
89 import is from 'shared/objectIs';
90 +import isArray from 'shared/isArray';
91 import {
92 markWorkInProgressReceivedUpdate,
93 checkIfWorkInProgressReceivedUpdate,
@@ -229,7 +230,7 @@ function updateHookTypesDev() {
230
231 function checkDepsAreArrayDev(deps: mixed) {
232 if (__DEV__) {
232 - if (deps !== undefined && deps !== null && !Array.isArray(deps)) {
233 + if (deps !== undefined && deps !== null && !isArray(deps)) {
234 // Verify deps, but only on mount to avoid extra checks.
235 // It's unlikely their type would change as usually you define them inline.
236 console.error(
packages/react-reconciler/src/ReactFiberHooks.old.js
+2 -1
@@ -87,6 +87,7 @@ import {
87 import invariant from 'shared/invariant';
88 import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
89 import is from 'shared/objectIs';
90 +import isArray from 'shared/isArray';
91 import {
92 markWorkInProgressReceivedUpdate,
93 checkIfWorkInProgressReceivedUpdate,
@@ -229,7 +230,7 @@ function updateHookTypesDev() {
230
231 function checkDepsAreArrayDev(deps: mixed) {
232 if (__DEV__) {
232 - if (deps !== undefined && deps !== null && !Array.isArray(deps)) {
233 + if (deps !== undefined && deps !== null && !isArray(deps)) {
234 // Verify deps, but only on mount to avoid extra checks.
235 // It's unlikely their type would change as usually you define them inline.
236 console.error(
packages/react-reconciler/src/ReactFiberReconciler.new.js
+6 -5
@@ -34,6 +34,7 @@ import {
34 } from './ReactWorkTags';
35 import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
36 import invariant from 'shared/invariant';
37 +import isArray from 'shared/isArray';
38 import {enableSchedulingProfiler} from 'shared/ReactFeatureFlags';
39 import ReactSharedInternals from 'shared/ReactSharedInternals';
40 import {getPublicInstance} from './ReactFiberHostConfig';
@@ -482,9 +483,9 @@ if (__DEV__) {
483 index: number,
484 ) => {
485 const key = path[index];
485 - const updated = Array.isArray(obj) ? obj.slice() : {...obj};
486 + const updated = isArray(obj) ? obj.slice() : {...obj};
487 if (index + 1 === path.length) {
487 - if (Array.isArray(updated)) {
488 + if (isArray(updated)) {
489 updated.splice(((key: any): number), 1);
490 } else {
491 delete updated[key];
@@ -510,12 +511,12 @@ if (__DEV__) {
511 index: number,
512 ) => {
513 const oldKey = oldPath[index];
513 - const updated = Array.isArray(obj) ? obj.slice() : {...obj};
514 + const updated = isArray(obj) ? obj.slice() : {...obj};
515 if (index + 1 === oldPath.length) {
516 const newKey = newPath[index];
517 // $FlowFixMe number or string is fine here
518 updated[newKey] = updated[oldKey];
518 - if (Array.isArray(updated)) {
519 + if (isArray(updated)) {
520 updated.splice(((oldKey: any): number), 1);
521 } else {
522 delete updated[oldKey];
@@ -564,7 +565,7 @@ if (__DEV__) {
565 return value;
566 }
567 const key = path[index];
567 - const updated = Array.isArray(obj) ? obj.slice() : {...obj};
568 + const updated = isArray(obj) ? obj.slice() : {...obj};
569 // $FlowFixMe number or string is fine here
570 updated[key] = copyWithSetImpl(obj[key], path, index + 1, value);
571 return updated;
packages/react-reconciler/src/ReactFiberReconciler.old.js
+6 -5
@@ -34,6 +34,7 @@ import {
34 } from './ReactWorkTags';
35 import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
36 import invariant from 'shared/invariant';
37 +import isArray from 'shared/isArray';
38 import {enableSchedulingProfiler} from 'shared/ReactFeatureFlags';
39 import ReactSharedInternals from 'shared/ReactSharedInternals';
40 import {getPublicInstance} from './ReactFiberHostConfig';
@@ -482,9 +483,9 @@ if (__DEV__) {
483 index: number,
484 ) => {
485 const key = path[index];
485 - const updated = Array.isArray(obj) ? obj.slice() : {...obj};
486 + const updated = isArray(obj) ? obj.slice() : {...obj};
487 if (index + 1 === path.length) {
487 - if (Array.isArray(updated)) {
488 + if (isArray(updated)) {
489 updated.splice(((key: any): number), 1);
490 } else {
491 delete updated[key];
@@ -510,12 +511,12 @@ if (__DEV__) {
511 index: number,
512 ) => {
513 const oldKey = oldPath[index];
513 - const updated = Array.isArray(obj) ? obj.slice() : {...obj};
514 + const updated = isArray(obj) ? obj.slice() : {...obj};
515 if (index + 1 === oldPath.length) {
516 const newKey = newPath[index];
517 // $FlowFixMe number or string is fine here
518 updated[newKey] = updated[oldKey];
518 - if (Array.isArray(updated)) {
519 + if (isArray(updated)) {
520 updated.splice(((oldKey: any): number), 1);
521 } else {
522 delete updated[oldKey];
@@ -564,7 +565,7 @@ if (__DEV__) {
565 return value;
566 }
567 const key = path[index];
567 - const updated = Array.isArray(obj) ? obj.slice() : {...obj};
568 + const updated = isArray(obj) ? obj.slice() : {...obj};
569 // $FlowFixMe number or string is fine here
570 updated[key] = copyWithSetImpl(obj[key], path, index + 1, value);
571 return updated;
packages/react-server-dom-relay/src/ReactFlightDOMRelayClientHostConfig.js
+3 -1
@@ -24,6 +24,8 @@ export {
24 requireModule,
25 } from 'ReactFlightDOMRelayClientIntegration';
26
27 +import isArray from 'shared/isArray';
28 +
29 export type {ModuleMetaData} from 'ReactFlightDOMRelayClientIntegration';
30
31 export type UninitializedModel = JSONValue;
@@ -35,7 +37,7 @@ function parseModelRecursively(response: Response, parentObj, value) {
37 return parseModelString(response, parentObj, value);
38 }
39 if (typeof value === 'object' && value !== null) {
38 - if (Array.isArray(value)) {
40 + if (isArray(value)) {
41 const parsedValue = [];
42 for (let i = 0; i < value.length; i++) {
43 (parsedValue: any)[i] = parseModelRecursively(
packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js
+2 -1
@@ -14,6 +14,7 @@ import type {Request, ReactModel} from 'react-server/src/ReactFlightServer';
14 import JSResourceReference from 'JSResourceReference';
15
16 import hasOwnProperty from 'shared/hasOwnProperty';
17 +import isArray from 'shared/isArray';
18
19 export type ModuleReference<T> = JSResourceReference<T>;
20
@@ -82,7 +83,7 @@ function convertModelToJSON(
83 ): JSONValue {
84 const json = resolveModelToJSON(request, parent, key, model);
85 if (typeof json === 'object' && json !== null) {
85 - if (Array.isArray(json)) {
86 + if (isArray(json)) {
87 const jsonArray: Array<JSONValue> = [];
88 for (let i = 0; i < json.length; i++) {
89 jsonArray[i] = convertModelToJSON(request, json, '' + i, json[i]);
packages/react-server-dom-webpack/src/ReactFlightWebpackPlugin.js
+3 -1
@@ -17,6 +17,8 @@ import NullDependency from 'webpack/lib/dependencies/NullDependency';
17 import AsyncDependenciesBlock from 'webpack/lib/AsyncDependenciesBlock';
18 import Template from 'webpack/lib/Template';
19
20 +import isArray from 'shared/isArray';
21 +
22 class ClientReferenceDependency extends ModuleDependency {
23 constructor(request) {
24 super(request);
@@ -76,7 +78,7 @@ export default class ReactFlightWebpackPlugin {
78 ];
79 } else if (
80 typeof options.clientReferences === 'string' ||
79 - !Array.isArray(options.clientReferences)
81 + !isArray(options.clientReferences)
82 ) {
83 this.clientReferences = [(options.clientReferences: $FlowFixMe)];
84 } else {
packages/react-server-native-relay/src/ReactFlightNativeRelayClientHostConfig.js
+3 -1
@@ -24,6 +24,8 @@ export {
24 requireModule,
25 } from 'ReactFlightNativeRelayClientIntegration';
26
27 +import isArray from 'shared/isArray';
28 +
29 export type {ModuleMetaData} from 'ReactFlightNativeRelayClientIntegration';
30
31 export type UninitializedModel = JSONValue;
@@ -35,7 +37,7 @@ function parseModelRecursively(response: Response, parentObj, value) {
37 return parseModelString(response, parentObj, value);
38 }
39 if (typeof value === 'object' && value !== null) {
38 - if (Array.isArray(value)) {
40 + if (isArray(value)) {
41 const parsedValue = [];
42 for (let i = 0; i < value.length; i++) {
43 (parsedValue: any)[i] = parseModelRecursively(
packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js
+2 -2
@@ -8,9 +8,9 @@
8 */
9
10 import type {RowEncoding, JSONValue} from './ReactFlightNativeRelayProtocol';
11 -
11 import type {Request, ReactModel} from 'react-server/src/ReactFlightServer';
12 import hasOwnProperty from 'shared/hasOwnProperty';
13 +import isArray from 'shared/isArray';
14 import JSResourceReferenceImpl from 'JSResourceReferenceImpl';
15
16 export type ModuleReference<T> = JSResourceReferenceImpl<T>;
@@ -80,7 +80,7 @@ function convertModelToJSON(
80 ): JSONValue {
81 const json = resolveModelToJSON(request, parent, key, model);
82 if (typeof json === 'object' && json !== null) {
83 - if (Array.isArray(json)) {
83 + if (isArray(json)) {
84 const jsonArray: Array<JSONValue> = [];
85 for (let i = 0; i < json.length; i++) {
86 jsonArray[i] = convertModelToJSON(request, json, '' + i, json[i]);
packages/react-server/src/ReactFizzServer.js
+2 -1
@@ -51,6 +51,7 @@ import {REACT_ELEMENT_TYPE, REACT_SUSPENSE_TYPE} from 'shared/ReactSymbols';
51 import ReactSharedInternals from 'shared/ReactSharedInternals';
52
53 import invariant from 'shared/invariant';
54 +import isArray from 'shared/isArray';
55
56 const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
57
@@ -287,7 +288,7 @@ function renderNode(request: Request, task: Task, node: ReactNodeList): void {
288 return;
289 }
290
290 - if (Array.isArray(node)) {
291 + if (isArray(node)) {
292 if (node.length > 0) {
293 for (let i = 0; i < node.length; i++) {
294 renderNode(request, task, node[i]);
packages/react-server/src/ReactFlightServer.js
+1 -2
@@ -44,8 +44,7 @@ import {
44
45 import ReactSharedInternals from 'shared/ReactSharedInternals';
46 import invariant from 'shared/invariant';
47 -
48 -const isArray = Array.isArray;
47 +import isArray from 'shared/isArray';
48
49 type ReactJSONValue =
50 | string
packages/react-test-renderer/src/ReactTestHostConfig.js
+2 -1
@@ -8,6 +8,7 @@
8 */
9
10 import {REACT_OPAQUE_ID_TYPE} from 'shared/ReactSymbols';
11 +import isArray from 'shared/isArray';
12 import {DefaultEventPriority} from 'react-reconciler/src/ReactEventPriorities';
13
14 export type Type = string;
@@ -84,7 +85,7 @@ export function appendChild(
85 child: Instance | TextInstance,
86 ): void {
87 if (__DEV__) {
87 - if (!Array.isArray(parentInstance.children)) {
88 + if (!isArray(parentInstance.children)) {
89 console.error(
90 'An invalid container has been provided. ' +
91 'This may indicate that another renderer is being used in addition to the test renderer. ' +
packages/react-test-renderer/src/ReactTestRenderer.js
+2 -1
@@ -43,6 +43,7 @@ import {
43 ScopeComponent,
44 } from 'react-reconciler/src/ReactWorkTags';
45 import invariant from 'shared/invariant';
46 +import isArray from 'shared/isArray';
47 import getComponentNameFromType from 'shared/getComponentNameFromType';
48 import ReactVersion from 'shared/ReactVersion';
49 import ReactSharedInternals from 'shared/ReactSharedInternals';
@@ -158,7 +159,7 @@ function flatten(arr) {
159 while (n.i < n.array.length) {
160 const el = n.array[n.i];
161 n.i += 1;
161 - if (Array.isArray(el)) {
162 + if (isArray(el)) {
163 stack.push(n);
164 stack.push({i: 0, array: el});
165 break;
packages/react/src/ReactChildren.js
+3 -2
@@ -10,6 +10,7 @@
10 import type {ReactNodeList} from 'shared/ReactTypes';
11
12 import invariant from 'shared/invariant';
13 +import isArray from 'shared/isArray';
14 import {
15 getIteratorFn,
16 REACT_ELEMENT_TYPE,
@@ -110,7 +111,7 @@ function mapIntoArray(
111 // so that it's consistent if the number of children grows:
112 const childKey =
113 nameSoFar === '' ? SEPARATOR + getElementKey(child, 0) : nameSoFar;
113 - if (Array.isArray(mappedChild)) {
114 + if (isArray(mappedChild)) {
115 let escapedChildKey = '';
116 if (childKey != null) {
117 escapedChildKey = escapeUserProvidedKey(childKey) + '/';
@@ -142,7 +143,7 @@ function mapIntoArray(
143 const nextNamePrefix =
144 nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR;
145
145 - if (Array.isArray(children)) {
146 + if (isArray(children)) {
147 for (let i = 0; i < children.length; i++) {
148 child = children[i];
149 nextName = nextNamePrefix + getElementKey(child, i);
packages/react/src/ReactElementValidator.js
+5 -4
@@ -23,6 +23,7 @@ import {
23 } from 'shared/ReactSymbols';
24 import {warnAboutSpreadingKeyToJSX} from 'shared/ReactFeatureFlags';
25 import checkPropTypes from 'shared/checkPropTypes';
26 +import isArray from 'shared/isArray';
27
28 import ReactCurrentOwner from './ReactCurrentOwner';
29 import {
@@ -168,7 +169,7 @@ function validateChildKeys(node, parentType) {
169 if (typeof node !== 'object') {
170 return;
171 }
171 - if (Array.isArray(node)) {
172 + if (isArray(node)) {
173 for (let i = 0; i < node.length; i++) {
174 const child = node[i];
175 if (isValidElement(child)) {
@@ -313,7 +314,7 @@ export function jsxWithValidation(
314 let typeString;
315 if (type === null) {
316 typeString = 'null';
316 - } else if (Array.isArray(type)) {
317 + } else if (isArray(type)) {
318 typeString = 'array';
319 } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) {
320 typeString = `<${getComponentNameFromType(type.type) || 'Unknown'} />`;
@@ -352,7 +353,7 @@ export function jsxWithValidation(
353 const children = props.children;
354 if (children !== undefined) {
355 if (isStaticChildren) {
355 - if (Array.isArray(children)) {
356 + if (isArray(children)) {
357 for (let i = 0; i < children.length; i++) {
358 validateChildKeys(children[i], type);
359 }
@@ -437,7 +438,7 @@ export function createElementWithValidation(type, props, children) {
438 let typeString;
439 if (type === null) {
440 typeString = 'null';
440 - } else if (Array.isArray(type)) {
441 + } else if (isArray(type)) {
442 typeString = 'array';
443 } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) {
444 typeString = `<${getComponentNameFromType(type.type) || 'Unknown'} />`;
packages/react/src/jsx/ReactJSXElementValidator.js
+4 -3
@@ -23,6 +23,7 @@ import {
23 } from 'shared/ReactSymbols';
24 import {warnAboutSpreadingKeyToJSX} from 'shared/ReactFeatureFlags';
25 import hasOwnProperty from 'shared/hasOwnProperty';
26 +import isArray from 'shared/isArray';
27 import {jsxDEV} from './ReactJSXElement';
28
29 import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame';
@@ -182,7 +183,7 @@ function validateChildKeys(node, parentType) {
183 if (typeof node !== 'object') {
184 return;
185 }
185 - if (Array.isArray(node)) {
186 + if (isArray(node)) {
187 for (let i = 0; i < node.length; i++) {
188 const child = node[i];
189 if (isValidElement(child)) {
@@ -329,7 +330,7 @@ export function jsxWithValidation(
330 let typeString;
331 if (type === null) {
332 typeString = 'null';
332 - } else if (Array.isArray(type)) {
333 + } else if (isArray(type)) {
334 typeString = 'array';
335 } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) {
336 typeString = `<${getComponentNameFromType(type.type) || 'Unknown'} />`;
@@ -366,7 +367,7 @@ export function jsxWithValidation(
367 const children = props.children;
368 if (children !== undefined) {
369 if (isStaticChildren) {
369 - if (Array.isArray(children)) {
370 + if (isArray(children)) {
371 for (let i = 0; i < children.length; i++) {
372 validateChildKeys(children[i], type);
373 }
packages/shared/isArray.js new
+19
@@ -0,0 +1,19 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its 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 +declare function isArray(a: mixed): boolean %checks(Array.isArray(a));
11 +
12 +const isArrayImpl = Array.isArray;
13 +
14 +// eslint-disable-next-line no-redeclare
15 +function isArray(a: mixed): boolean {
16 + return isArrayImpl(a);
17 +}
18 +
19 +export default isArray;