From 1123e684c5a05db4fb15f0f2f8d1d0dc179ff102 Mon Sep 17 00:00:00 2001 From: Justin Grant Date: Sun, 15 Aug 2021 20:45:11 -0700 Subject: [PATCH] Replace `'' + obj` pattern with `''.concat(obj)` Using the `+` operator to concatenate strings and objects is problematic because `+` calls `valueOf` which will throw for some types. See #20594 for details. This commit globally replaces `'' + obj` with `''.concat(obj)`, which does the same thing but doesn't call `valueOf` before converting to a string. It also updates the code example in the lint rule that encouaged use of this problematic pattern. --- .../fixtures/error-handling/index.js | 2 +- .../cjs/react-jsx-dev-runtime.development.js | 6 +++--- .../cjs/react-jsx-runtime.development.js | 6 +++--- .../cjs/react-jsx-dev-runtime.development.js | 6 +++--- .../cjs/react-jsx-runtime.development.js | 6 +++--- .../cjs/react-jsx-dev-runtime.development.js | 6 +++--- .../cjs/react-jsx-runtime.development.js | 6 +++--- .../cjs/react-jsx-dev-runtime.development.js | 6 +++--- .../cjs/react-jsx-runtime.development.js | 6 +++--- .../react-devtools-extensions/src/main.js | 2 +- .../src/backend/legacy/renderer.js | 2 +- .../src/backend/renderer.js | 2 +- .../src/backend/utils.js | 6 +++--- .../views/ErrorBoundary/ErrorBoundary.js | 2 +- .../src/devtools/views/utils.js | 4 ++-- packages/react-devtools-shared/src/utils.js | 2 +- .../src/__tests__/ReactDOMInput-test.js | 2 +- .../src/__tests__/ReactDOMTextarea-test.js | 2 +- .../src/__tests__/ReactMultiChildText-test.js | 4 ++-- .../src/client/DOMPropertyOperations.js | 14 ++++++------- .../react-dom/src/client/ReactDOMComponent.js | 10 +++++----- .../src/client/ReactDOMHostConfig.js | 4 ++-- .../react-dom/src/client/ReactDOMInput.js | 2 +- .../react-dom/src/client/ToStringValue.js | 2 +- .../src/client/inputValueTracking.js | 6 +++--- .../src/server/DOMMarkupOperations.js | 2 +- .../src/server/ReactDOMServerFormatConfig.js | 20 +++++++++---------- .../src/server/ReactPartialRenderer.js | 10 +++++----- .../src/server/escapeTextForBrowser.js | 4 ++-- .../src/shared/dangerousStyleValue.js | 2 +- .../src/test-utils/ReactTestUtils.js | 2 +- .../react-noop-renderer/flight-modules.js | 2 +- .../react-noop-renderer/npm/flight-modules.js | 2 +- .../src/createReactNoop.js | 4 ++-- .../src/ReactChildFiber.new.js | 10 +++++----- .../src/ReactChildFiber.old.js | 10 +++++----- packages/react-reconciler/src/ReactPortal.js | 2 +- .../src/__tests__/ReactIncremental-test.js | 4 ++-- .../src/__tests__/ReactMemo-test.js | 2 +- .../src/__tests__/ReactPersistent-test.js | 2 +- .../ReactFlightDOMRelayServerHostConfig.js | 2 +- .../src/ReactFlightWebpackPlugin.js | 2 +- .../src/__tests__/ReactFlightDOM-test.js | 2 +- .../ReactFlightNativeRelayServerHostConfig.js | 2 +- packages/react-server/src/ReactFizzServer.js | 2 +- .../react-server/src/ReactFlightServer.js | 6 +++--- .../src/ReactTestRenderer.js | 2 +- packages/react/src/ReactChildren.js | 6 +++--- packages/react/src/ReactElement.js | 12 +++++------ packages/react/src/jsx/ReactJSXElement.js | 8 ++++---- packages/shared/consoleWithStackDev.js | 2 +- scripts/error-codes/extract-errors.js | 2 +- ...no-primitive-constructors-test.internal.js | 4 ++-- .../eslint-rules/no-primitive-constructors.js | 2 +- scripts/merge-fork/merge-fork.js | 4 ++-- 55 files changed, 126 insertions(+), 126 deletions(-) diff --git a/fixtures/dom/src/components/fixtures/error-handling/index.js b/fixtures/dom/src/components/fixtures/error-handling/index.js index 5bbeec7de447eb..d0d8627b16d311 100644 --- a/fixtures/dom/src/components/fixtures/error-handling/index.js +++ b/fixtures/dom/src/components/fixtures/error-handling/index.js @@ -41,7 +41,7 @@ class ErrorBoundary extends React.Component { if (this.state.error) { return

Captured an error: {this.state.error.message}

; } else { - return

Captured an error: {'' + this.state.error}

; + return

Captured an error: {''.concat(this.state.error)}

; } } if (this.state.shouldThrow) { diff --git a/fixtures/legacy-jsx-runtimes/react-14/cjs/react-jsx-dev-runtime.development.js b/fixtures/legacy-jsx-runtimes/react-14/cjs/react-jsx-dev-runtime.development.js index 31238ef27cf806..be8fe12161d0f8 100644 --- a/fixtures/legacy-jsx-runtimes/react-14/cjs/react-jsx-dev-runtime.development.js +++ b/fixtures/legacy-jsx-runtimes/react-14/cjs/react-jsx-dev-runtime.development.js @@ -104,7 +104,7 @@ function printWarning(level, format, args) { } var argsWithFormat = args.map(function (item) { - return '' + item; + return ''.concat(item); }); // Careful: RN currently depends on this prefix argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it @@ -483,11 +483,11 @@ function jsxDEV(type, config, maybeKey, source, self) { // key is explicitly declared to be undefined or not. if (maybeKey !== undefined) { - key = '' + maybeKey; + key = ''.concat(maybeKey); } if (hasValidKey(config)) { - key = '' + config.key; + key = ''.concat(config.key); } if (hasValidRef(config)) { diff --git a/fixtures/legacy-jsx-runtimes/react-14/cjs/react-jsx-runtime.development.js b/fixtures/legacy-jsx-runtimes/react-14/cjs/react-jsx-runtime.development.js index 5658993188aece..92c101038edaf0 100644 --- a/fixtures/legacy-jsx-runtimes/react-14/cjs/react-jsx-runtime.development.js +++ b/fixtures/legacy-jsx-runtimes/react-14/cjs/react-jsx-runtime.development.js @@ -103,7 +103,7 @@ function printWarning(level, format, args) { } var argsWithFormat = args.map(function (item) { - return '' + item; + return ''.concat(item); }); // Careful: RN currently depends on this prefix argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it @@ -487,11 +487,11 @@ function jsxDEV(type, config, maybeKey, source, self) { // key is explicitly declared to be undefined or not. if (maybeKey !== undefined) { - key = '' + maybeKey; + key = ''.concat(maybeKey); } if (hasValidKey(config)) { - key = '' + config.key; + key = ''.concat(config.key); } if (hasValidRef(config)) { diff --git a/fixtures/legacy-jsx-runtimes/react-15/cjs/react-jsx-dev-runtime.development.js b/fixtures/legacy-jsx-runtimes/react-15/cjs/react-jsx-dev-runtime.development.js index ecad786788f052..eee05e356f439d 100644 --- a/fixtures/legacy-jsx-runtimes/react-15/cjs/react-jsx-dev-runtime.development.js +++ b/fixtures/legacy-jsx-runtimes/react-15/cjs/react-jsx-dev-runtime.development.js @@ -109,7 +109,7 @@ function printWarning(level, format, args) { } var argsWithFormat = args.map(function (item) { - return '' + item; + return ''.concat(item); }); // Careful: RN currently depends on this prefix argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it @@ -488,11 +488,11 @@ function jsxDEV(type, config, maybeKey, source, self) { // key is explicitly declared to be undefined or not. if (maybeKey !== undefined) { - key = '' + maybeKey; + key = ''.concat(maybeKey); } if (hasValidKey(config)) { - key = '' + config.key; + key = ''.concat(config.key); } if (hasValidRef(config)) { diff --git a/fixtures/legacy-jsx-runtimes/react-15/cjs/react-jsx-runtime.development.js b/fixtures/legacy-jsx-runtimes/react-15/cjs/react-jsx-runtime.development.js index 9fce32b1c1e4ca..4c6ce3c86669a7 100644 --- a/fixtures/legacy-jsx-runtimes/react-15/cjs/react-jsx-runtime.development.js +++ b/fixtures/legacy-jsx-runtimes/react-15/cjs/react-jsx-runtime.development.js @@ -108,7 +108,7 @@ function printWarning(level, format, args) { } var argsWithFormat = args.map(function (item) { - return '' + item; + return ''.concat(item); }); // Careful: RN currently depends on this prefix argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it @@ -492,11 +492,11 @@ function jsxDEV(type, config, maybeKey, source, self) { // key is explicitly declared to be undefined or not. if (maybeKey !== undefined) { - key = '' + maybeKey; + key = ''.concat(maybeKey); } if (hasValidKey(config)) { - key = '' + config.key; + key = ''.concat(config.key); } if (hasValidRef(config)) { diff --git a/fixtures/legacy-jsx-runtimes/react-16/cjs/react-jsx-dev-runtime.development.js b/fixtures/legacy-jsx-runtimes/react-16/cjs/react-jsx-dev-runtime.development.js index 880e9b652f0ba6..4dc95bb27d7602 100644 --- a/fixtures/legacy-jsx-runtimes/react-16/cjs/react-jsx-dev-runtime.development.js +++ b/fixtures/legacy-jsx-runtimes/react-16/cjs/react-jsx-dev-runtime.development.js @@ -115,7 +115,7 @@ function printWarning(level, format, args) { } var argsWithFormat = args.map(function (item) { - return '' + item; + return ''.concat(item); }); // Careful: RN currently depends on this prefix argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it @@ -509,11 +509,11 @@ function jsxDEV(type, config, maybeKey, source, self) { // key is explicitly declared to be undefined or not. if (maybeKey !== undefined) { - key = '' + maybeKey; + key = ''.concat(maybeKey); } if (hasValidKey(config)) { - key = '' + config.key; + key = ''.concat(config.key); } if (hasValidRef(config)) { diff --git a/fixtures/legacy-jsx-runtimes/react-16/cjs/react-jsx-runtime.development.js b/fixtures/legacy-jsx-runtimes/react-16/cjs/react-jsx-runtime.development.js index 76e6f2457b9c4f..e2a031f1108ff9 100644 --- a/fixtures/legacy-jsx-runtimes/react-16/cjs/react-jsx-runtime.development.js +++ b/fixtures/legacy-jsx-runtimes/react-16/cjs/react-jsx-runtime.development.js @@ -114,7 +114,7 @@ function printWarning(level, format, args) { } var argsWithFormat = args.map(function (item) { - return '' + item; + return ''.concat(item); }); // Careful: RN currently depends on this prefix argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it @@ -513,11 +513,11 @@ function jsxDEV(type, config, maybeKey, source, self) { // key is explicitly declared to be undefined or not. if (maybeKey !== undefined) { - key = '' + maybeKey; + key = ''.concat(maybeKey); } if (hasValidKey(config)) { - key = '' + config.key; + key = ''.concat(config.key); } if (hasValidRef(config)) { diff --git a/fixtures/legacy-jsx-runtimes/react-17/cjs/react-jsx-dev-runtime.development.js b/fixtures/legacy-jsx-runtimes/react-17/cjs/react-jsx-dev-runtime.development.js index 3b7122293e1bc9..5400ccbf57a655 100644 --- a/fixtures/legacy-jsx-runtimes/react-17/cjs/react-jsx-dev-runtime.development.js +++ b/fixtures/legacy-jsx-runtimes/react-17/cjs/react-jsx-dev-runtime.development.js @@ -107,7 +107,7 @@ function printWarning(level, format, args) { } var argsWithFormat = args.map(function (item) { - return '' + item; + return ''.concat(item); }); // Careful: RN currently depends on this prefix argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it @@ -815,11 +815,11 @@ function jsxDEV(type, config, maybeKey, source, self) { // key is explicitly declared to be undefined or not. if (maybeKey !== undefined) { - key = '' + maybeKey; + key = ''.concat(maybeKey); } if (hasValidKey(config)) { - key = '' + config.key; + key = ''.concat(config.key); } if (hasValidRef(config)) { diff --git a/fixtures/legacy-jsx-runtimes/react-17/cjs/react-jsx-runtime.development.js b/fixtures/legacy-jsx-runtimes/react-17/cjs/react-jsx-runtime.development.js index 690bebdf52523a..368daed1928eb3 100644 --- a/fixtures/legacy-jsx-runtimes/react-17/cjs/react-jsx-runtime.development.js +++ b/fixtures/legacy-jsx-runtimes/react-17/cjs/react-jsx-runtime.development.js @@ -107,7 +107,7 @@ function printWarning(level, format, args) { } var argsWithFormat = args.map(function (item) { - return '' + item; + return ''.concat(item); }); // Careful: RN currently depends on this prefix argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it @@ -815,11 +815,11 @@ function jsxDEV(type, config, maybeKey, source, self) { // key is explicitly declared to be undefined or not. if (maybeKey !== undefined) { - key = '' + maybeKey; + key = ''.concat(maybeKey); } if (hasValidKey(config)) { - key = '' + config.key; + key = ''.concat(config.key); } if (hasValidRef(config)) { diff --git a/packages/react-devtools-extensions/src/main.js b/packages/react-devtools-extensions/src/main.js index 514e48514d785c..277f8676561df2 100644 --- a/packages/react-devtools-extensions/src/main.js +++ b/packages/react-devtools-extensions/src/main.js @@ -82,7 +82,7 @@ function createPanelIfReactLoaded() { function initBridgeAndStore() { const port = chrome.runtime.connect({ - name: '' + tabId, + name: ''.concat(tabId), }); // Looks like `port.onDisconnect` does not trigger on in-tab navigation like new URL or back/forward navigation, // so it makes no sense to handle it here. diff --git a/packages/react-devtools-shared/src/backend/legacy/renderer.js b/packages/react-devtools-shared/src/backend/legacy/renderer.js index 7b612ff346171e..01cafdf3bfd07e 100644 --- a/packages/react-devtools-shared/src/backend/legacy/renderer.js +++ b/packages/react-devtools-shared/src/backend/legacy/renderer.js @@ -63,7 +63,7 @@ function getData(internalInstance: InternalInstance) { // != used deliberately here to catch undefined and null if (internalInstance._currentElement != null) { if (internalInstance._currentElement.key) { - key = '' + internalInstance._currentElement.key; + key = ''.concat(internalInstance._currentElement.key); } const elementType = internalInstance._currentElement.type; diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index 62341ce300ec00..9e407eadda83ec 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -1838,7 +1838,7 @@ export function attach( // This check is a guard to handle a React element that has been modified // in such a way as to bypass the default stringification of the "key" property. - const keyString = key === null ? null : '' + key; + const keyString = key === null ? null : ''.concat(key); const keyStringID = getStringID(keyString); pushOperation(TREE_OPERATION_ADD); diff --git a/packages/react-devtools-shared/src/backend/utils.js b/packages/react-devtools-shared/src/backend/utils.js index 60fabfa03c8931..b852e49c725b7d 100644 --- a/packages/react-devtools-shared/src/backend/utils.js +++ b/packages/react-devtools-shared/src/backend/utils.js @@ -169,7 +169,7 @@ export function format( let formatted: string = typeof maybeMessage === 'symbol' ? maybeMessage.toString() - : '' + maybeMessage; + : ''.concat(maybeMessage); // If the first argument is a string, check for substitutions. if (typeof maybeMessage === 'string') { @@ -205,14 +205,14 @@ export function format( const arg = args[i]; // Symbols cannot be concatenated with Strings. - formatted += ' ' + (typeof arg === 'symbol' ? arg.toString() : arg); + formatted += ' ' + (typeof arg === 'symbol' ? arg.toString() : ''.concat(arg)); } } // Update escaped %% values. formatted = formatted.replace(/%{2,2}/g, '%'); - return '' + formatted; + return ''.concat(formatted); } export function isSynchronousXHRSupported(): boolean { diff --git a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ErrorBoundary.js b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ErrorBoundary.js index c7aa20dcd5902e..ae02af3680fc40 100644 --- a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ErrorBoundary.js +++ b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ErrorBoundary.js @@ -46,7 +46,7 @@ export default class ErrorBoundary extends Component { error !== null && error.hasOwnProperty('message') ? error.message - : '' + error; + : ''.concat(error); const callStack = typeof error === 'object' && diff --git a/packages/react-devtools-shared/src/devtools/views/utils.js b/packages/react-devtools-shared/src/devtools/views/utils.js index b326996daa05af..c5460c37a128c5 100644 --- a/packages/react-devtools-shared/src/devtools/views/utils.js +++ b/packages/react-devtools-shared/src/devtools/views/utils.js @@ -19,8 +19,8 @@ export function alphaSortEntries( ): number { const a = entryA[0]; const b = entryB[0]; - if ('' + +a === a) { - if ('' + +b !== b) { + if (''.concat(+a) === a) { + if (''.concat(+b) !== b) { return -1; } return +a < +b ? -1 : 1; diff --git a/packages/react-devtools-shared/src/utils.js b/packages/react-devtools-shared/src/utils.js index 573679f635ab8f..e2ae9bd20683e2 100644 --- a/packages/react-devtools-shared/src/utils.js +++ b/packages/react-devtools-shared/src/utils.js @@ -805,7 +805,7 @@ export function formatDataForPreview( return data; default: try { - return truncateForDisplay('' + data); + return truncateForDisplay(''.concat(data)); } catch (error) { return 'unserializable'; } diff --git a/packages/react-dom/src/__tests__/ReactDOMInput-test.js b/packages/react-dom/src/__tests__/ReactDOMInput-test.js index 018dd14697f08a..e35831de0225fa 100644 --- a/packages/react-dom/src/__tests__/ReactDOMInput-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMInput-test.js @@ -1575,7 +1575,7 @@ describe('ReactDOMInput', () => { return value; }, set: function(val) { - value = '' + val; + value = ''.concat(val); log.push('set property value'); }, }); diff --git a/packages/react-dom/src/__tests__/ReactDOMTextarea-test.js b/packages/react-dom/src/__tests__/ReactDOMTextarea-test.js index 4d56f53d9e40c6..cd87ebd4881dd2 100644 --- a/packages/react-dom/src/__tests__/ReactDOMTextarea-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMTextarea-test.js @@ -142,7 +142,7 @@ describe('ReactDOMTextarea', () => { return value; }, set: function(val) { - value = '' + val; + value = ''.concat(val); counter++; }, }); diff --git a/packages/react-dom/src/__tests__/ReactMultiChildText-test.js b/packages/react-dom/src/__tests__/ReactMultiChildText-test.js index 467cbf59c2e067..a8d13d15e7b3f0 100644 --- a/packages/react-dom/src/__tests__/ReactMultiChildText-test.js +++ b/packages/react-dom/src/__tests__/ReactMultiChildText-test.js @@ -44,7 +44,7 @@ const expectChildren = function(container, children) { } else { expect(textNode != null).toBe(true); expect(textNode.nodeType).toBe(3); - expect(textNode.data).toBe('' + children); + expect(textNode.data).toBe(''.concat(children)); } } else { let mountIndex = 0; @@ -55,7 +55,7 @@ const expectChildren = function(container, children) { if (typeof child === 'string') { textNode = outerNode.childNodes[mountIndex]; expect(textNode.nodeType).toBe(3); - expect(textNode.data).toBe('' + child); + expect(textNode.data).toBe(''.concat(child)); mountIndex++; } else { const elementDOMNode = outerNode.childNodes[mountIndex]; diff --git a/packages/react-dom/src/client/DOMPropertyOperations.js b/packages/react-dom/src/client/DOMPropertyOperations.js index 2dcb1ace8ab9f5..9bd3b5f09c7bdf 100644 --- a/packages/react-dom/src/client/DOMPropertyOperations.js +++ b/packages/react-dom/src/client/DOMPropertyOperations.js @@ -44,7 +44,7 @@ export function getValueForProperty( // If we haven't fully disabled javascript: URLs, and if // the hydration is successful of a javascript: URL, we // still want to warn on the client. - sanitizeURL('' + (expected: any)); + sanitizeURL(''.concat((expected: any))); } const attributeName = propertyInfo.attributeName; @@ -60,7 +60,7 @@ export function getValueForProperty( if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { return value; } - if (value === '' + (expected: any)) { + if (value === ''.concat((expected: any))) { return expected; } return value; @@ -85,7 +85,7 @@ export function getValueForProperty( if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { return stringValue === null ? expected : stringValue; - } else if (stringValue === '' + (expected: any)) { + } else if (stringValue === ''.concat((expected: any))) { return expected; } else { return stringValue; @@ -119,7 +119,7 @@ export function getValueForAttribute( return expected === undefined ? undefined : null; } const value = node.getAttribute(name); - if (value === '' + (expected: any)) { + if (value === ''.concat((expected: any))) { return expected; } return value; @@ -155,7 +155,7 @@ export function setValueForProperty( } else { node.setAttribute( attributeName, - enableTrustedTypesIntegration ? (value: any) : '' + (value: any), + enableTrustedTypesIntegration ? (value: any) : ''.concat((value: any)), ); } } @@ -187,11 +187,11 @@ export function setValueForProperty( attributeValue = ''; } else { // `setAttribute` with objects becomes only `[object]` in IE8/9, - // ('' + value) makes it output the correct toString()-value. + // (''.concat(value)) makes it output the correct toString()-value. if (enableTrustedTypesIntegration) { attributeValue = (value: any); } else { - attributeValue = '' + (value: any); + attributeValue = ''.concat((value: any)); } if (propertyInfo.sanitizeURL) { sanitizeURL(attributeValue.toString()); diff --git a/packages/react-dom/src/client/ReactDOMComponent.js b/packages/react-dom/src/client/ReactDOMComponent.js index 7820978957107c..16f8abd7cd3f7d 100644 --- a/packages/react-dom/src/client/ReactDOMComponent.js +++ b/packages/react-dom/src/client/ReactDOMComponent.js @@ -140,7 +140,7 @@ if (__DEV__) { normalizeMarkupForTextOrAttribute = function(markup: mixed): string { const markupString = - typeof markup === 'string' ? markup : '' + (markup: any); + typeof markup === 'string' ? markup : ''.concat((markup: any)); return markupString .replace(NORMALIZE_NEWLINES_REGEX, '\n') .replace(NORMALIZE_NULL_AND_REPLACEMENT_REGEX, ''); @@ -303,7 +303,7 @@ function setInitialDOMProperties( setTextContent(domElement, nextProp); } } else if (typeof nextProp === 'number') { - setTextContent(domElement, '' + nextProp); + setTextContent(domElement, ''.concat(nextProp)); } } else if ( propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || @@ -748,7 +748,7 @@ export function diffProperties( } } else if (propKey === CHILDREN) { if (typeof nextProp === 'string' || typeof nextProp === 'number') { - (updatePayload = updatePayload || []).push(propKey, '' + nextProp); + (updatePayload = updatePayload || []).push(propKey, ''.concat(nextProp)); } } else if ( propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || @@ -981,11 +981,11 @@ export function diffHydratedProperties( updatePayload = [CHILDREN, nextProp]; } } else if (typeof nextProp === 'number') { - if (domElement.textContent !== '' + nextProp) { + if (domElement.textContent !== ''.concat(nextProp)) { if (__DEV__ && !suppressHydrationWarning) { warnForTextDifference(domElement.textContent, nextProp); } - updatePayload = [CHILDREN, '' + nextProp]; + updatePayload = [CHILDREN, ''.concat(nextProp)]; } } } else if (registrationNameDependencies.hasOwnProperty(propKey)) { diff --git a/packages/react-dom/src/client/ReactDOMHostConfig.js b/packages/react-dom/src/client/ReactDOMHostConfig.js index 74877c1591e756..5457938ee68ba7 100644 --- a/packages/react-dom/src/client/ReactDOMHostConfig.js +++ b/packages/react-dom/src/client/ReactDOMHostConfig.js @@ -275,7 +275,7 @@ export function createInstance( typeof props.children === 'string' || typeof props.children === 'number' ) { - const string = '' + props.children; + const string = ''.concat(props.children); const ownAncestorInfo = updatedAncestorInfo( hostContextDev.ancestorInfo, type, @@ -330,7 +330,7 @@ export function prepareUpdate( (typeof newProps.children === 'string' || typeof newProps.children === 'number') ) { - const string = '' + newProps.children; + const string = ''.concat(newProps.children); const ownAncestorInfo = updatedAncestorInfo( hostContextDev.ancestorInfo, type, diff --git a/packages/react-dom/src/client/ReactDOMInput.js b/packages/react-dom/src/client/ReactDOMInput.js index c1afd277e3e930..c32682f0cd4cfe 100644 --- a/packages/react-dom/src/client/ReactDOMInput.js +++ b/packages/react-dom/src/client/ReactDOMInput.js @@ -366,7 +366,7 @@ function updateNamedCousins(rootNode, props) { // document. Let's just use the local `querySelectorAll` to ensure we don't // miss anything. const group = queryRoot.querySelectorAll( - 'input[name=' + JSON.stringify('' + name) + '][type="radio"]', + 'input[name=' + JSON.stringify(''.concat(name)) + '][type="radio"]', ); for (let i = 0; i < group.length; i++) { diff --git a/packages/react-dom/src/client/ToStringValue.js b/packages/react-dom/src/client/ToStringValue.js index 41826cd404e05f..7c77adbf9b599e 100644 --- a/packages/react-dom/src/client/ToStringValue.js +++ b/packages/react-dom/src/client/ToStringValue.js @@ -19,7 +19,7 @@ export opaque type ToStringValue = // around this limitation, we use an opaque type that can only be obtained by // passing the value through getToStringValue first. export function toString(value: ToStringValue): string { - return '' + (value: any); + return ''.concat((value: any)); } export function getToStringValue(value: mixed): ToStringValue { diff --git a/packages/react-dom/src/client/inputValueTracking.js b/packages/react-dom/src/client/inputValueTracking.js index 54c850662ab2b5..f174d481d80311 100644 --- a/packages/react-dom/src/client/inputValueTracking.js +++ b/packages/react-dom/src/client/inputValueTracking.js @@ -55,7 +55,7 @@ function trackValueOnNode(node: any): ?ValueTracker { valueField, ); - let currentValue = '' + node[valueField]; + let currentValue = ''.concat(node[valueField]); // if someone has already defined a value or Safari, then bail // and don't track value will cause over reporting of changes, @@ -76,7 +76,7 @@ function trackValueOnNode(node: any): ?ValueTracker { return get.call(this); }, set: function(value) { - currentValue = '' + value; + currentValue = ''.concat(value); set.call(this, value); }, }); @@ -93,7 +93,7 @@ function trackValueOnNode(node: any): ?ValueTracker { return currentValue; }, setValue(value) { - currentValue = '' + value; + currentValue = ''.concat(value); }, stopTracking() { detachTracker(node); diff --git a/packages/react-dom/src/server/DOMMarkupOperations.js b/packages/react-dom/src/server/DOMMarkupOperations.js index 014e6355319266..8b12b5257d7bde 100644 --- a/packages/react-dom/src/server/DOMMarkupOperations.js +++ b/packages/react-dom/src/server/DOMMarkupOperations.js @@ -44,7 +44,7 @@ export function createMarkupForProperty(name: string, value: mixed): string { return attributeName + '=""'; } else { if (propertyInfo.sanitizeURL) { - value = '' + (value: any); + value = ''.concat((value: any)); sanitizeURL(value); } return attributeName + '=' + quoteAttributeValueForBrowser(value); diff --git a/packages/react-dom/src/server/ReactDOMServerFormatConfig.js b/packages/react-dom/src/server/ReactDOMServerFormatConfig.js index 9232106aac362d..2bef2e355a2378 100644 --- a/packages/react-dom/src/server/ReactDOMServerFormatConfig.js +++ b/packages/react-dom/src/server/ReactDOMServerFormatConfig.js @@ -310,7 +310,7 @@ function pushStyle( if (isCustomProperty) { nameChunk = stringToChunk(escapeTextForBrowser(styleName)); valueChunk = stringToChunk( - escapeTextForBrowser(('' + styleValue).trim()), + escapeTextForBrowser((''.concat(styleValue)).trim()), ); } else { if (__DEV__) { @@ -325,11 +325,11 @@ function pushStyle( ) { valueChunk = stringToChunk(styleValue + 'px'); // Presumes implicit 'px' suffix for unitless numbers } else { - valueChunk = stringToChunk('' + styleValue); + valueChunk = stringToChunk(''.concat(styleValue)); } } else { valueChunk = stringToChunk( - escapeTextForBrowser(('' + styleValue).trim()), + escapeTextForBrowser((''.concat(styleValue)).trim()), ); } } @@ -476,7 +476,7 @@ function pushAttribute( break; default: if (propertyInfo.sanitizeURL) { - value = '' + (value: any); + value = ''.concat((value: any)); sanitizeURL(value); } target.push( @@ -557,7 +557,7 @@ function pushInnerHTML( ); const html = innerHTML.__html; if (html !== null && html !== undefined) { - target.push(stringToChunk('' + html)); + target.push(stringToChunk(''.concat(html))); } } } @@ -745,7 +745,7 @@ function pushStartOption( if (selectedValue !== null) { let stringValue; if (value !== null) { - stringValue = '' + value; + stringValue = ''.concat(value); } else { if (__DEV__) { if (innerHTML !== null) { @@ -763,7 +763,7 @@ function pushStartOption( if (isArray(selectedValue)) { // multiple for (let i = 0; i < selectedValue.length; i++) { - const v = '' + selectedValue[i]; + const v = ''.concat(selectedValue[i]); if (v === stringValue) { target.push(selectedMarkerAttribute); break; @@ -975,9 +975,9 @@ function pushStartTextArea( children.length <= 1, '