diff --git a/packages/eslint-plugin/tests/rules/only-throw-error.test.ts b/packages/eslint-plugin/tests/rules/only-throw-error.test.ts index 6f60f01b8405..500454d0a9cb 100644 --- a/packages/eslint-plugin/tests/rules/only-throw-error.test.ts +++ b/packages/eslint-plugin/tests/rules/only-throw-error.test.ts @@ -191,6 +191,19 @@ throw new Map(); }, { code: ` +function func() { + let err: Promise | Promise; + throw err; +} + `, + options: [ + { + allow: ['Promise'], + }, + ], + }, + { + code: ` try { } catch (e) { throw e; @@ -615,6 +628,24 @@ function fun(t: T): void { }, { code: ` +function func() { + let err: Promise | Promise | void; + throw err; +} + `, + errors: [ + { + messageId: 'object', + }, + ], + options: [ + { + allow: ['Promise'], + }, + ], + }, + { + code: ` class UnknownError implements Error {} throw new UnknownError(); `, diff --git a/packages/type-utils/src/TypeOrValueSpecifier.ts b/packages/type-utils/src/TypeOrValueSpecifier.ts index bbfb99ddcc78..553c8a4225bf 100644 --- a/packages/type-utils/src/TypeOrValueSpecifier.ts +++ b/packages/type-utils/src/TypeOrValueSpecifier.ts @@ -169,6 +169,10 @@ export function typeMatchesSpecifier( specifier: TypeOrValueSpecifier, program: ts.Program, ): boolean { + if (tsutils.isUnionType(type)) { + return type.types.every(t => typeMatchesSpecifier(t, specifier, program)); + } + const wholeTypeMatches = ((): boolean => { if (tsutils.isIntrinsicErrorType(type)) { return false; diff --git a/packages/type-utils/tests/TypeOrValueSpecifier.test.ts b/packages/type-utils/tests/TypeOrValueSpecifier.test.ts index a28d22f36b71..3d3429fbb3d1 100644 --- a/packages/type-utils/tests/TypeOrValueSpecifier.test.ts +++ b/packages/type-utils/tests/TypeOrValueSpecifier.test.ts @@ -179,6 +179,7 @@ describe('TypeOrValueSpecifier', () => { ['interface Foo {prop: string}; type Test = Foo;', 'RegExp'], ['type Test = RegExp;', 'Foo'], ['type Test = RegExp;', 'BigInt'], + ['type Test = RegExp | BigInt;', 'BigInt'], ] as const satisfies [string, TypeOrValueSpecifier][])( "doesn't match a mismatched universal string specifier: %s\n\t%s", ([code, typeOrValueSpecifier], { expect }) => { @@ -267,6 +268,10 @@ describe('TypeOrValueSpecifier', () => { 'interface Foo {prop: string}; type Test = Foo;', { from: 'file', name: 'Bar' }, ], + [ + 'interface Foo {prop: string}; type Test = Foo | string;', + { from: 'file', name: 'Foo' }, + ], [ 'interface Foo {prop: string}; type Test = Foo;', { from: 'file', name: ['Bar', 'Baz'] }, @@ -306,6 +311,7 @@ describe('TypeOrValueSpecifier', () => { it.for([ ['type Test = RegExp;', { from: 'lib', name: 'BigInt' }], + ['type Test = RegExp | BigInt;', { from: 'lib', name: 'BigInt' }], ['type Test = RegExp;', { from: 'lib', name: ['BigInt', 'Date'] }], ] as const satisfies [string, TypeOrValueSpecifier][])( "doesn't match a mismatched lib specifier: %s\n\t%s", @@ -326,6 +332,7 @@ describe('TypeOrValueSpecifier', () => { it.for([ ['type Test = string;', { from: 'lib', name: 'number' }], + ['type Test = string | number;', { from: 'lib', name: 'number' }], ['type Test = string;', { from: 'lib', name: ['number', 'boolean'] }], ] as const satisfies [string, TypeOrValueSpecifier][])( "doesn't match a mismatched intrinsic type specifier: %s\n\t%s", @@ -545,6 +552,10 @@ describe('TypeOrValueSpecifier', () => { 'import type {Node} from "typescript"; type Test = Node;', { from: 'package', name: 'Symbol', package: 'typescript' }, ], + [ + 'import type {Node} from "typescript"; type Test = Node | Symbol;', + { from: 'package', name: 'Node', package: 'typescript' }, + ], [ 'import type {Node} from "typescript"; type Test = Node;', { from: 'package', name: ['Symbol', 'Checker'], package: 'typescript' },