Skip to content

Commit de90529

Browse files
committed
Use String(value) for coercion in non-prod files
This commit switches non-production code from `'' + value` (which throws for Temporal objects and symbols) to instead use `String(value)` which won't throw for these or other future plus-phobic types. "Non-produciton code" includes anything not bundled into user apps: * Tests and test utilities. Note that I didn't change legacy React test fixtures because I assumed it was good for those files to act just like old React, including coercion behavior. * Build scripts * Dev tools package - In addition to switching to `String`, I also removed special-case code for coercing symbols which is now unnecessary.
1 parent 64a72a4 commit de90529

File tree

23 files changed

+47
-61
lines changed

23 files changed

+47
-61
lines changed

dangerfile.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ function row(result) {
102102
let headSha;
103103
let baseSha;
104104
try {
105-
headSha = (readFileSync(HEAD_DIR + '/COMMIT_SHA') + '').trim();
106-
baseSha = (readFileSync(BASE_DIR + '/COMMIT_SHA') + '').trim();
105+
headSha = String(readFileSync(HEAD_DIR + '/COMMIT_SHA')).trim();
106+
baseSha = String(readFileSync(BASE_DIR + '/COMMIT_SHA')).trim();
107107
} catch {
108108
warn(
109109
"Failed to read build artifacts. It's possible a build configuration " +

fixtures/dom/src/components/fixtures/error-handling/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class ErrorBoundary extends React.Component {
4141
if (this.state.error) {
4242
return <p>Captured an error: {this.state.error.message}</p>;
4343
} else {
44-
return <p>Captured an error: {'' + this.state.error}</p>;
44+
return <p>Captured an error: {String(this.state.error)}</p>;
4545
}
4646
}
4747
if (this.state.shouldThrow) {

packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ describe('ReactHooksInspectionIntegration', () => {
615615
expect(tree[0].id).toEqual(0);
616616
expect(tree[0].isStateEditable).toEqual(false);
617617
expect(tree[0].name).toEqual('OpaqueIdentifier');
618-
expect((tree[0].value + '').startsWith('c_')).toBe(true);
618+
expect(String(tree[0].value).startsWith('c_')).toBe(true);
619619

620620
expect(tree[1]).toEqual({
621621
id: 1,
@@ -646,7 +646,7 @@ describe('ReactHooksInspectionIntegration', () => {
646646
expect(tree[0].id).toEqual(0);
647647
expect(tree[0].isStateEditable).toEqual(false);
648648
expect(tree[0].name).toEqual('OpaqueIdentifier');
649-
expect((tree[0].value + '').startsWith('c_')).toBe(true);
649+
expect(String(tree[0].value).startsWith('c_')).toBe(true);
650650

651651
expect(tree[1]).toEqual({
652652
id: 1,

packages/react-devtools-extensions/src/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ function createPanelIfReactLoaded() {
9494

9595
function initBridgeAndStore() {
9696
const port = chrome.runtime.connect({
97-
name: '' + tabId,
97+
name: String(tabId),
9898
});
9999
// Looks like `port.onDisconnect` does not trigger on in-tab navigation like new URL or back/forward navigation,
100100
// so it makes no sense to handle it here.

packages/react-devtools-shared/src/backend/legacy/renderer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ function getData(internalInstance: InternalInstance) {
6363
// != used deliberately here to catch undefined and null
6464
if (internalInstance._currentElement != null) {
6565
if (internalInstance._currentElement.key) {
66-
key = '' + internalInstance._currentElement.key;
66+
key = String(internalInstance._currentElement.key);
6767
}
6868

6969
const elementType = internalInstance._currentElement.type;

packages/react-devtools-shared/src/backend/renderer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1847,7 +1847,7 @@ export function attach(
18471847

18481848
// This check is a guard to handle a React element that has been modified
18491849
// in such a way as to bypass the default stringification of the "key" property.
1850-
const keyString = key === null ? null : '' + key;
1850+
const keyString = key === null ? null : String(key);
18511851
const keyStringID = getStringID(keyString);
18521852

18531853
pushOperation(TREE_OPERATION_ADD);

packages/react-devtools-shared/src/backend/utils.js

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,7 @@ export function format(
166166
): string {
167167
const args = inputArgs.slice();
168168

169-
// Symbols cannot be concatenated with Strings.
170-
let formatted: string =
171-
typeof maybeMessage === 'symbol'
172-
? maybeMessage.toString()
173-
: '' + maybeMessage;
169+
let formatted: string = String(maybeMessage);
174170

175171
// If the first argument is a string, check for substitutions.
176172
if (typeof maybeMessage === 'string') {
@@ -203,17 +199,14 @@ export function format(
203199
// Arguments that remain after formatting.
204200
if (args.length) {
205201
for (let i = 0; i < args.length; i++) {
206-
const arg = args[i];
207-
208-
// Symbols cannot be concatenated with Strings.
209-
formatted += ' ' + (typeof arg === 'symbol' ? arg.toString() : arg);
202+
formatted += ' ' + String(args[i]);
210203
}
211204
}
212205

213206
// Update escaped %% values.
214207
formatted = formatted.replace(/%{2,2}/g, '%');
215208

216-
return '' + formatted;
209+
return String(formatted);
217210
}
218211

219212
export function isSynchronousXHRSupported(): boolean {

packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ErrorBoundary.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export default class ErrorBoundary extends Component<Props, State> {
4646
error !== null &&
4747
error.hasOwnProperty('message')
4848
? error.message
49-
: '' + error;
49+
: String(error);
5050

5151
const callStack =
5252
typeof error === 'object' &&

packages/react-devtools-shared/src/devtools/views/utils.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ export function alphaSortEntries(
1919
): number {
2020
const a = entryA[0];
2121
const b = entryB[0];
22-
if ('' + +a === a) {
23-
if ('' + +b !== b) {
22+
if (String(+a) === a) {
23+
if (String(+b) !== b) {
2424
return -1;
2525
}
2626
return +a < +b ? -1 : 1;

packages/react-devtools-shared/src/hook.js

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,7 @@ export function installHook(target: any): DevToolsHook | null {
180180
const args = inputArgs.slice();
181181

182182
// Symbols cannot be concatenated with Strings.
183-
let formatted: string =
184-
typeof maybeMessage === 'symbol'
185-
? maybeMessage.toString()
186-
: '' + maybeMessage;
183+
let formatted = String(maybeMessage);
187184

188185
// If the first argument is a string, check for substitutions.
189186
if (typeof maybeMessage === 'string') {
@@ -216,17 +213,14 @@ export function installHook(target: any): DevToolsHook | null {
216213
// Arguments that remain after formatting.
217214
if (args.length) {
218215
for (let i = 0; i < args.length; i++) {
219-
const arg = args[i];
220-
221-
// Symbols cannot be concatenated with Strings.
222-
formatted += ' ' + (typeof arg === 'symbol' ? arg.toString() : arg);
216+
formatted += ' ' + String(args[i]);
223217
}
224218
}
225219

226220
// Update escaped %% values.
227221
formatted = formatted.replace(/%{2,2}/g, '%');
228222

229-
return '' + formatted;
223+
return String(formatted);
230224
}
231225

232226
let unpatchFn = null;

0 commit comments

Comments
 (0)