From a3c037b7ce6bd801dc3d388896a1ba9e84f45327 Mon Sep 17 00:00:00 2001 From: Justin Grant Date: Mon, 16 Aug 2021 11:31:27 -0700 Subject: [PATCH] Change `''.concat(value)` to `String(value)` `''.concat(value)` violates current Flow definitons that require args to concat to be strings only, even though the MDN docs and ES spec allow args to be any type. See https://github.com/facebook/flow/issues/8728. To avoid depending on a change to Flow, this commit changes `''.concat(value)` to `String(value)` and removes the lint rule that prohibits use of String(value). This rule was added in #9082. The other rules in that PR (for Boolean and Number constructors) are not changed in this commit, only the rule for String. If it's decided that using `concat` is better, simply omit this commit and use the previous one instead. --- .../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 | 16 +++++++-------- .../react-dom/src/client/ReactDOMComponent.js | 13 +++++------- .../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 | 15 +++++--------- .../src/ReactChildFiber.old.js | 15 +++++--------- packages/react-reconciler/src/ReactPortal.js | 2 +- .../src/__tests__/ReactIncremental-test.js | 4 ++-- .../src/__tests__/ReactMemo-test.js | 4 +--- .../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 | 13 +----------- .../eslint-rules/no-primitive-constructors.js | 9 --------- scripts/merge-fork/merge-fork.js | 4 ++-- 55 files changed, 124 insertions(+), 161 deletions(-) diff --git a/fixtures/dom/src/components/fixtures/error-handling/index.js b/fixtures/dom/src/components/fixtures/error-handling/index.js index d0d8627b16d31..904bef4788c56 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: {''.concat(this.state.error)}

; + return

Captured an error: {String(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 be8fe12161d0f..e694606414e59 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 ''.concat(item); + return String(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 = ''.concat(maybeKey); + key = String(maybeKey); } if (hasValidKey(config)) { - key = ''.concat(config.key); + key = String(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 92c101038edaf..f3a17615e35b6 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 ''.concat(item); + return String(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 = ''.concat(maybeKey); + key = String(maybeKey); } if (hasValidKey(config)) { - key = ''.concat(config.key); + key = String(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 eee05e356f439..518afed134824 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 ''.concat(item); + return String(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 = ''.concat(maybeKey); + key = String(maybeKey); } if (hasValidKey(config)) { - key = ''.concat(config.key); + key = String(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 4c6ce3c86669a..ce286380a13c3 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 ''.concat(item); + return String(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 = ''.concat(maybeKey); + key = String(maybeKey); } if (hasValidKey(config)) { - key = ''.concat(config.key); + key = String(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 4dc95bb27d760..46d9cf79601c2 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 ''.concat(item); + return String(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 = ''.concat(maybeKey); + key = String(maybeKey); } if (hasValidKey(config)) { - key = ''.concat(config.key); + key = String(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 e2a031f1108ff..c4c32c586296e 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 ''.concat(item); + return String(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 = ''.concat(maybeKey); + key = String(maybeKey); } if (hasValidKey(config)) { - key = ''.concat(config.key); + key = String(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 5400ccbf57a65..be78410909213 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 ''.concat(item); + return String(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 = ''.concat(maybeKey); + key = String(maybeKey); } if (hasValidKey(config)) { - key = ''.concat(config.key); + key = String(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 368daed1928eb..7faf6cc46f5bf 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 ''.concat(item); + return String(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 = ''.concat(maybeKey); + key = String(maybeKey); } if (hasValidKey(config)) { - key = ''.concat(config.key); + key = String(config.key); } if (hasValidRef(config)) { diff --git a/packages/react-devtools-extensions/src/main.js b/packages/react-devtools-extensions/src/main.js index 277f8676561df..dbc621c4e5916 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: ''.concat(tabId), + name: String(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 01cafdf3bfd07..7b2b6d79856a2 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 = ''.concat(internalInstance._currentElement.key); + key = String(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 9e407eadda83e..bf16c953d7848 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 : ''.concat(key); + const keyString = key === null ? null : String(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 66661f31e2ce2..de97b280a3e26 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() - : ''.concat(maybeMessage); + : String(maybeMessage); // If the first argument is a string, check for substitutions. if (typeof maybeMessage === 'string') { @@ -206,14 +206,14 @@ export function format( // Symbols cannot be concatenated with Strings. formatted += - ' ' + (typeof arg === 'symbol' ? arg.toString() : ''.concat(arg)); + ' ' + (typeof arg === 'symbol' ? arg.toString() : String(arg)); } } // Update escaped %% values. formatted = formatted.replace(/%{2,2}/g, '%'); - return ''.concat(formatted); + return String(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 ae02af3680fc4..ea4f54b1a9b8b 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 - : ''.concat(error); + : String(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 c5460c37a128c..035d9f83a3bc5 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 (''.concat(+a) === a) { - if (''.concat(+b) !== b) { + if (String(+a) === a) { + if (String(+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 e2ae9bd20683e..0772c3064c58f 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(''.concat(data)); + return truncateForDisplay(String(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 f364ee7f52302..6eac5bf68ee39 100644 --- a/packages/react-dom/src/__tests__/ReactDOMInput-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMInput-test.js @@ -1647,7 +1647,7 @@ describe('ReactDOMInput', () => { return value; }, set: function(val) { - value = ''.concat(val); + value = String(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 cd87ebd4881dd..ac7d8d063d794 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 = ''.concat(val); + value = String(val); counter++; }, }); diff --git a/packages/react-dom/src/__tests__/ReactMultiChildText-test.js b/packages/react-dom/src/__tests__/ReactMultiChildText-test.js index a8d13d15e7b3f..6da148a93dbbb 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(''.concat(children)); + expect(textNode.data).toBe(String(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(''.concat(child)); + expect(textNode.data).toBe(String(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 57532897b4f71..8b79b429e41e8 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(''.concat((expected: any))); + sanitizeURL(String((expected: any))); } const attributeName = propertyInfo.attributeName; @@ -60,7 +60,7 @@ export function getValueForProperty( if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { return value; } - if (value === ''.concat((expected: any))) { + if (value === String((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 === ''.concat((expected: any))) { + } else if (stringValue === String((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 === ''.concat((expected: any))) { + if (value === String((expected: any))) { return expected; } return value; @@ -155,9 +155,7 @@ export function setValueForProperty( } else { node.setAttribute( attributeName, - enableTrustedTypesIntegration - ? (value: any) - : ''.concat((value: any)), + enableTrustedTypesIntegration ? (value: any) : String((value: any)), ); } } @@ -189,11 +187,11 @@ export function setValueForProperty( attributeValue = ''; } else { // `setAttribute` with objects becomes only `[object]` in IE8/9, - // (''.concat(value)) makes it output the correct toString()-value. + // (String(value)) makes it output the correct toString()-value. if (enableTrustedTypesIntegration) { attributeValue = (value: any); } else { - attributeValue = ''.concat((value: any)); + attributeValue = String((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 6aa3e49698ca3..572a324d2e3fb 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 : ''.concat((markup: any)); + typeof markup === 'string' ? markup : String((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, ''.concat(nextProp)); + setTextContent(domElement, String(nextProp)); } } else if ( propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || @@ -748,10 +748,7 @@ export function diffProperties( } } else if (propKey === CHILDREN) { if (typeof nextProp === 'string' || typeof nextProp === 'number') { - (updatePayload = updatePayload || []).push( - propKey, - ''.concat(nextProp), - ); + (updatePayload = updatePayload || []).push(propKey, String(nextProp)); } } else if ( propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || @@ -984,11 +981,11 @@ export function diffHydratedProperties( updatePayload = [CHILDREN, nextProp]; } } else if (typeof nextProp === 'number') { - if (domElement.textContent !== ''.concat(nextProp)) { + if (domElement.textContent !== String(nextProp)) { if (__DEV__ && !suppressHydrationWarning) { warnForTextDifference(domElement.textContent, nextProp); } - updatePayload = [CHILDREN, ''.concat(nextProp)]; + updatePayload = [CHILDREN, String(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 5457938ee68ba..3841e5f4af006 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 = ''.concat(props.children); + const string = String(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 = ''.concat(newProps.children); + const string = String(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 c32682f0cd4cf..7516e39f04c89 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(''.concat(name)) + '][type="radio"]', + 'input[name=' + JSON.stringify(String(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 7c77adbf9b599..97860183db3c9 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 ''.concat((value: any)); + return String((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 f174d481d8031..647c7b63147ab 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 = ''.concat(node[valueField]); + let currentValue = String(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 = ''.concat(value); + currentValue = String(value); set.call(this, value); }, }); @@ -93,7 +93,7 @@ function trackValueOnNode(node: any): ?ValueTracker { return currentValue; }, setValue(value) { - currentValue = ''.concat(value); + currentValue = String(value); }, stopTracking() { detachTracker(node); diff --git a/packages/react-dom/src/server/DOMMarkupOperations.js b/packages/react-dom/src/server/DOMMarkupOperations.js index 8b12b5257d7bd..6a5256cb924fa 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 = ''.concat((value: any)); + value = String((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 22fd36a16010f..977d51fb57c08 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(''.concat(styleValue).trim()), + escapeTextForBrowser(String(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(''.concat(styleValue)); + valueChunk = stringToChunk(String(styleValue)); } } else { valueChunk = stringToChunk( - escapeTextForBrowser(''.concat(styleValue).trim()), + escapeTextForBrowser(String(styleValue).trim()), ); } } @@ -476,7 +476,7 @@ function pushAttribute( break; default: if (propertyInfo.sanitizeURL) { - value = ''.concat((value: any)); + value = String((value: any)); sanitizeURL(value); } target.push( @@ -557,7 +557,7 @@ function pushInnerHTML( ); const html = innerHTML.__html; if (html !== null && html !== undefined) { - target.push(stringToChunk(''.concat(html))); + target.push(stringToChunk(String(html))); } } } @@ -745,7 +745,7 @@ function pushStartOption( if (selectedValue !== null) { let stringValue; if (value !== null) { - stringValue = ''.concat(value); + stringValue = String(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 = ''.concat(selectedValue[i]); + const v = String(selectedValue[i]); if (v === stringValue) { target.push(selectedMarkerAttribute); break; @@ -975,9 +975,9 @@ function pushStartTextArea( children.length <= 1, '