add rules to prefer Error objects to be thrown and rejected (#54229)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/54229

Changelog: [General][Added] Added eslint rule to warn when a non-error is being thrown from a function or rejected for a promise.

Reviewed By: huntie

Differential Revision: D85237916

fbshipit-source-id: e0e4fbc6b4620a19be1959d3953856c7e44ad4e0
This commit is contained in:
Vitali Zaidman
2025-10-23 06:42:55 -07:00
committed by meta-codesync[bot]
parent 9cadfe6607
commit 94995fdd9f
7 changed files with 20 additions and 9 deletions
+3
View File
@@ -35,6 +35,9 @@ module.exports = {
// Flow handles these checks for us, so they aren't required
'no-undef': 'off',
'no-unreachable': 'off',
// Throwing from function or rejecting promises with non-error values could result in unclear error stack traces and lead to harder debugging
'prefer-promise-reject-errors': 'error',
'no-throw-literal': 'error',
},
},
{
@@ -332,7 +332,9 @@ class DebuggingOverlayRegistry {
instance.measure((x, y, width, height, left, top) => {
// measure can execute callback without any values provided to signal error.
if (left == null || top == null || width == null || height == null) {
reject('Unexpectedly failed to call measure on an instance.');
reject(
new Error('Unexpectedly failed to call measure on an instance.'),
);
}
resolve({
@@ -480,7 +482,11 @@ class DebuggingOverlayRegistry {
width == null ||
height == null
) {
reject('Unexpectedly failed to call measure on an instance.');
reject(
new Error(
'Unexpectedly failed to call measure on an instance.',
),
);
}
resolve({x: left, y: top, width, height});
@@ -23,7 +23,9 @@ export function unstable_hasComponent(name: string): boolean {
hasNativeComponent = global.__nativeComponentRegistry__hasComponent(name);
componentNameToExists.set(name, hasNativeComponent);
} else {
throw `unstable_hasComponent('${name}'): Global function is not registered`;
throw new Error(
`unstable_hasComponent('${name}'): Global function is not registered`,
);
}
}
return hasNativeComponent;
+2 -2
View File
@@ -30,7 +30,7 @@ function getCodegen() /*: $FlowFixMe */ {
RNCodegen = require('@react-native/codegen/lib/generators/RNCodegen.js');
}
if (!RNCodegen) {
throw 'RNCodegen not found.';
throw new Error('RNCodegen not found.');
}
return RNCodegen;
}
@@ -45,7 +45,7 @@ function getCombineJSToSchema() /*: $FlowFixMe */ {
combineJSToSchema = require('@react-native/codegen/lib/cli/combine/combine-js-to-schema.js');
}
if (!combineJSToSchema) {
throw 'combine-js-to-schema not found.';
throw new Error('combine-js-to-schema not found.');
}
return combineJSToSchema;
}
@@ -38,7 +38,7 @@ const codegenLog = (text /*: string */, info /*: boolean */ = false) => {
function readPkgJsonInDirectory(dir /*: string */) /*: $FlowFixMe */ {
const pkgJsonPath = path.join(dir, 'package.json');
if (!fs.existsSync(pkgJsonPath)) {
throw `[Codegen] Error: ${pkgJsonPath} does not exist.`;
throw new Error(`[Codegen] Error: ${pkgJsonPath} does not exist.`);
}
return JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));
}
@@ -174,7 +174,7 @@ function findProjectRootLibraries(
}
if (typeof pkgJson.codegenConfig !== 'object') {
throw 'The "codegenConfig" field must be an Object.';
throw new Error('The "codegenConfig" field must be an Object.');
}
return extractLibrariesFromJSON(pkgJson, projectRoot);
@@ -30,5 +30,5 @@ export function takeScreenshot(
if (NativeModule != null) {
return NativeModule.takeScreenshot(id, options);
}
return Promise.reject();
return Promise.reject(new Error('ScreenshotManager is not defined.'));
}
@@ -34,7 +34,7 @@ function blobToBase64(blob: Blob) {
if (typeof result === 'string') {
resolve(result);
} else {
reject('error: incompatible types');
reject(new Error('error: incompatible types'));
}
};
reader.readAsDataURL(blob);