diff --git a/packages/eslint-plugin/src/rules/no-throw-literal.ts b/packages/eslint-plugin/src/rules/no-throw-literal.ts index b8017c4483a..acaa4adf987 100644 --- a/packages/eslint-plugin/src/rules/no-throw-literal.ts +++ b/packages/eslint-plugin/src/rules/no-throw-literal.ts @@ -61,40 +61,6 @@ export default util.createRule({ return false; } - function tryGetThrowArgumentType(node: TSESTree.Node): ts.Type | null { - switch (node.type) { - case AST_NODE_TYPES.Identifier: - case AST_NODE_TYPES.CallExpression: - case AST_NODE_TYPES.NewExpression: - case AST_NODE_TYPES.MemberExpression: - case AST_NODE_TYPES.TSAsExpression: { - const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node); - return checker.getTypeAtLocation(tsNode); - } - - case AST_NODE_TYPES.AssignmentExpression: - return tryGetThrowArgumentType(node.right); - - case AST_NODE_TYPES.SequenceExpression: - return tryGetThrowArgumentType( - node.expressions[node.expressions.length - 1], - ); - - case AST_NODE_TYPES.LogicalExpression: { - const left = tryGetThrowArgumentType(node.left); - return left ?? tryGetThrowArgumentType(node.right); - } - - case AST_NODE_TYPES.ConditionalExpression: { - const consequent = tryGetThrowArgumentType(node.consequent); - return consequent ?? tryGetThrowArgumentType(node.alternate); - } - - default: - return null; - } - } - function checkThrowArgument(node: TSESTree.Node): void { if ( node.type === AST_NODE_TYPES.AwaitExpression || @@ -103,20 +69,20 @@ export default util.createRule({ return; } - const type = tryGetThrowArgumentType(node); - if (type) { - if (type.flags & ts.TypeFlags.Undefined) { - context.report({ node, messageId: 'undef' }); - return; - } + const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node); + const type = checker.getTypeAtLocation(tsNode); - if ( - util.isTypeAnyType(type) || - util.isTypeUnknownType(type) || - isErrorLike(type) - ) { - return; - } + if (type.flags & ts.TypeFlags.Undefined) { + context.report({ node, messageId: 'undef' }); + return; + } + + if ( + util.isTypeAnyType(type) || + util.isTypeUnknownType(type) || + isErrorLike(type) + ) { + return; } context.report({ node, messageId: 'object' }); diff --git a/packages/eslint-plugin/tests/rules/no-throw-literal.test.ts b/packages/eslint-plugin/tests/rules/no-throw-literal.test.ts index 883894bf2a1..c8ee6e3eb9c 100644 --- a/packages/eslint-plugin/tests/rules/no-throw-literal.test.ts +++ b/packages/eslint-plugin/tests/rules/no-throw-literal.test.ts @@ -61,14 +61,13 @@ throw new CustomError(); ` class CustomError1 extends Error {} class CustomError2 extends CustomError1 {} -throw new CustomError(); +throw new CustomError2(); `, 'throw (foo = new Error());', 'throw (1, 2, new Error());', "throw 'literal' && new Error();", "throw new Error() || 'literal';", - "throw foo ? new Error() : 'literal';", - "throw foo ? 'literal' : new Error();", + 'throw foo ? new Error() : new Error();', ` function* foo() { let index = 0; @@ -112,6 +111,18 @@ declare const foo: Error | string; throw foo as Error; `, 'throw new Error() as Error;', + ` +declare const nullishError: Error | undefined; +throw nullishError ?? new Error(); + `, + ` +declare const nullishError: Error | undefined; +throw nullishError || new Error(); + `, + ` +declare const nullishError: Error | undefined; +throw nullishError ? nullishError : new Error(); + `, ], invalid: [ { @@ -207,19 +218,31 @@ throw a + 'b'; }, { code: "throw 'literal' && 'not an Error';", - errors: [ - { - messageId: 'object', - }, - ], + errors: [{ messageId: 'object' }], + }, + { + code: "throw 'literal' || new Error();", + errors: [{ messageId: 'object' }], + }, + { + code: "throw new Error() && 'literal';", + errors: [{ messageId: 'object' }], + }, + { + code: "throw 'literal' ?? new Error();", + errors: [{ messageId: 'object' }], }, { code: "throw foo ? 'not an Error' : 'literal';", - errors: [ - { - messageId: 'object', - }, - ], + errors: [{ messageId: 'object' }], + }, + { + code: "throw foo ? new Error() : 'literal';", + errors: [{ messageId: 'object' }], + }, + { + code: "throw foo ? 'literal' : new Error();", + errors: [{ messageId: 'object' }], }, { code: 'throw `${err}`;',