mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
The goal is to improve speed of the development by inlining and DCE unused branches. We have the ability to preserve some variable names and pretty print in the production version so might as well do the same with DEV.
181 lines
6.1 KiB
JavaScript
181 lines
6.1 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow
|
|
*/
|
|
|
|
/*
|
|
* The `'' + value` pattern (used in perf-sensitive code) throws for Symbol
|
|
* and Temporal.* types. See https://github.com/facebook/react/pull/22064.
|
|
*
|
|
* The functions in this module will throw an easier-to-understand,
|
|
* easier-to-debug exception with a clear errors message message explaining the
|
|
* problem. (Instead of a confusing exception thrown inside the implementation
|
|
* of the `value` object).
|
|
*/
|
|
|
|
// $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible.
|
|
function typeName(value: mixed): string {
|
|
if (__DEV__) {
|
|
// toStringTag is needed for namespaced types like Temporal.Instant
|
|
const hasToStringTag = typeof Symbol === 'function' && Symbol.toStringTag;
|
|
const type =
|
|
(hasToStringTag && (value: any)[Symbol.toStringTag]) ||
|
|
(value: any).constructor.name ||
|
|
'Object';
|
|
// $FlowFixMe[incompatible-return]
|
|
return type;
|
|
}
|
|
}
|
|
|
|
// $FlowFixMe[incompatible-return] only called in DEV, so void return is not possible.
|
|
function willCoercionThrow(value: mixed): boolean {
|
|
if (__DEV__) {
|
|
try {
|
|
testStringCoercion(value);
|
|
return false;
|
|
} catch (e) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** @noinline */
|
|
function testStringCoercion(value: mixed) {
|
|
// If you ended up here by following an exception call stack, here's what's
|
|
// happened: you supplied an object or symbol value to React (as a prop, key,
|
|
// DOM attribute, CSS property, string ref, etc.) and when React tried to
|
|
// coerce it to a string using `'' + value`, an exception was thrown.
|
|
//
|
|
// The most common types that will cause this exception are `Symbol` instances
|
|
// and Temporal objects like `Temporal.Instant`. But any object that has a
|
|
// `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this
|
|
// exception. (Library authors do this to prevent users from using built-in
|
|
// numeric operators like `+` or comparison operators like `>=` because custom
|
|
// methods are needed to perform accurate arithmetic or comparison.)
|
|
//
|
|
// To fix the problem, coerce this object or symbol value to a string before
|
|
// passing it to React. The most reliable way is usually `String(value)`.
|
|
//
|
|
// To find which value is throwing, check the browser or debugger console.
|
|
// Before this exception was thrown, there should be `console.error` output
|
|
// that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the
|
|
// problem and how that type was used: key, atrribute, input value prop, etc.
|
|
// In most cases, this console output also shows the component and its
|
|
// ancestor components where the exception happened.
|
|
//
|
|
// eslint-disable-next-line react-internal/safe-string-coercion
|
|
return '' + (value: any);
|
|
}
|
|
|
|
export function checkAttributeStringCoercion(
|
|
value: mixed,
|
|
attributeName: string,
|
|
): void | string {
|
|
if (__DEV__) {
|
|
if (willCoercionThrow(value)) {
|
|
console.error(
|
|
'The provided `%s` attribute is an unsupported type %s.' +
|
|
' This value must be coerced to a string before using it here.',
|
|
attributeName,
|
|
typeName(value),
|
|
);
|
|
return testStringCoercion(value); // throw (to help callers find troubleshooting comments)
|
|
}
|
|
}
|
|
}
|
|
|
|
export function checkKeyStringCoercion(value: mixed): void | string {
|
|
if (__DEV__) {
|
|
if (willCoercionThrow(value)) {
|
|
console.error(
|
|
'The provided key is an unsupported type %s.' +
|
|
' This value must be coerced to a string before using it here.',
|
|
typeName(value),
|
|
);
|
|
return testStringCoercion(value); // throw (to help callers find troubleshooting comments)
|
|
}
|
|
}
|
|
}
|
|
|
|
export function checkPropStringCoercion(
|
|
value: mixed,
|
|
propName: string,
|
|
): void | string {
|
|
if (__DEV__) {
|
|
if (willCoercionThrow(value)) {
|
|
console.error(
|
|
'The provided `%s` prop is an unsupported type %s.' +
|
|
' This value must be coerced to a string before using it here.',
|
|
propName,
|
|
typeName(value),
|
|
);
|
|
return testStringCoercion(value); // throw (to help callers find troubleshooting comments)
|
|
}
|
|
}
|
|
}
|
|
|
|
export function checkOptionStringCoercion(
|
|
value: mixed,
|
|
propName: string,
|
|
): void | string {
|
|
if (__DEV__) {
|
|
if (willCoercionThrow(value)) {
|
|
console.error(
|
|
'The provided `%s` option is an unsupported type %s.' +
|
|
' This value must be coerced to a string before using it here.',
|
|
propName,
|
|
typeName(value),
|
|
);
|
|
return testStringCoercion(value); // throw (to help callers find troubleshooting comments)
|
|
}
|
|
}
|
|
}
|
|
|
|
export function checkCSSPropertyStringCoercion(
|
|
value: mixed,
|
|
propName: string,
|
|
): void | string {
|
|
if (__DEV__) {
|
|
if (willCoercionThrow(value)) {
|
|
console.error(
|
|
'The provided `%s` CSS property is an unsupported type %s.' +
|
|
' This value must be coerced to a string before using it here.',
|
|
propName,
|
|
typeName(value),
|
|
);
|
|
return testStringCoercion(value); // throw (to help callers find troubleshooting comments)
|
|
}
|
|
}
|
|
}
|
|
|
|
export function checkHtmlStringCoercion(value: mixed): void | string {
|
|
if (__DEV__) {
|
|
if (willCoercionThrow(value)) {
|
|
console.error(
|
|
'The provided HTML markup uses a value of unsupported type %s.' +
|
|
' This value must be coerced to a string before using it here.',
|
|
typeName(value),
|
|
);
|
|
return testStringCoercion(value); // throw (to help callers find troubleshooting comments)
|
|
}
|
|
}
|
|
}
|
|
|
|
export function checkFormFieldValueStringCoercion(value: mixed): void | string {
|
|
if (__DEV__) {
|
|
if (willCoercionThrow(value)) {
|
|
console.error(
|
|
'Form field values (value, checked, defaultValue, or defaultChecked props)' +
|
|
' must be strings, not %s.' +
|
|
' This value must be coerced to a string before using it here.',
|
|
typeName(value),
|
|
);
|
|
return testStringCoercion(value); // throw (to help callers find troubleshooting comments)
|
|
}
|
|
}
|
|
}
|