Skip to content

Commit c1fe3ea

Browse files
feat(eslint-plugin): [only-throw-error] add allow option (typescript-eslint#10221)
* feat(eslint-plugin): [only-throw-error] add allowThrowing option * ts ignore * Update only-throw-error.shot * review * Add to TypeOrValueSpecifier.mdx options --------- Co-authored-by: Josh Goldberg <git@joshuakgoldberg.com>
1 parent 3664c20 commit c1fe3ea

File tree

7 files changed

+229
-4
lines changed

7 files changed

+229
-4
lines changed

docs/packages/type-utils/TypeOrValueSpecifier.mdx

+1
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,5 @@ Universal string specifiers will be removed in a future major version of typescr
132132

133133
- [`@typescript-eslint/no-floating-promises` > `allowForKnownSafeCalls`](/rules/no-floating-promises#allowforknownsafecalls)
134134
- [`@typescript-eslint/no-floating-promises` > `allowForKnownSafePromises`](/rules/no-floating-promises#allowforknownsafepromises)
135+
- [`@typescript-eslint/only-throw-error` > `allow`](/rules/only-throw-error/#allow)
135136
- [`@typescript-eslint/prefer-readonly-parameter-types` > `allow`](/rules/prefer-readonly-parameter-types/#allow)

packages/eslint-plugin/docs/rules/only-throw-error.mdx

+24-2
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,27 @@ This rule adds the following options:
102102

103103
```ts
104104
interface Options {
105+
/**
106+
* Type specifiers that can be thrown.
107+
*/
108+
allow?: (
109+
| {
110+
from: 'file';
111+
name: [string, ...string[]] | string;
112+
path?: string;
113+
}
114+
| {
115+
from: 'lib';
116+
name: [string, ...string[]] | string;
117+
}
118+
| {
119+
from: 'package';
120+
name: [string, ...string[]] | string;
121+
package: string;
122+
}
123+
| string
124+
)[];
125+
105126
/**
106127
* Whether to always allow throwing values typed as `any`.
107128
*/
@@ -114,8 +135,9 @@ interface Options {
114135
}
115136

116137
const defaultOptions: Options = {
117-
allowThrowingAny: false,
118-
allowThrowingUnknown: false,
138+
allow: [],
139+
allowThrowingAny: true,
140+
allowThrowingUnknown: true,
119141
};
120142
```
121143

packages/eslint-plugin/src/rules/only-throw-error.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,23 @@ import type { TSESTree } from '@typescript-eslint/utils';
33
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
44
import * as ts from 'typescript';
55

6+
import type { TypeOrValueSpecifier } from '../util';
7+
68
import {
79
createRule,
810
getParserServices,
911
isErrorLike,
1012
isTypeAnyType,
1113
isTypeUnknownType,
14+
typeMatchesSomeSpecifier,
15+
typeOrValueSpecifiersSchema,
1216
} from '../util';
1317

1418
type MessageIds = 'object' | 'undef';
1519

1620
type Options = [
1721
{
22+
allow?: TypeOrValueSpecifier[];
1823
allowThrowingAny?: boolean;
1924
allowThrowingUnknown?: boolean;
2025
},
@@ -39,6 +44,10 @@ export default createRule<Options, MessageIds>({
3944
type: 'object',
4045
additionalProperties: false,
4146
properties: {
47+
allow: {
48+
...typeOrValueSpecifiersSchema,
49+
description: 'Type specifiers that can be thrown.',
50+
},
4251
allowThrowingAny: {
4352
type: 'boolean',
4453
description:
@@ -55,13 +64,14 @@ export default createRule<Options, MessageIds>({
5564
},
5665
defaultOptions: [
5766
{
67+
allow: [],
5868
allowThrowingAny: true,
5969
allowThrowingUnknown: true,
6070
},
6171
],
6272
create(context, [options]) {
6373
const services = getParserServices(context);
64-
74+
const allow = options.allow;
6575
function checkThrowArgument(node: TSESTree.Node): void {
6676
if (
6777
node.type === AST_NODE_TYPES.AwaitExpression ||
@@ -72,6 +82,10 @@ export default createRule<Options, MessageIds>({
7282

7383
const type = services.getTypeAtLocation(node);
7484

85+
if (typeMatchesSomeSpecifier(type, allow, services.program)) {
86+
return;
87+
}
88+
7589
if (type.flags & ts.TypeFlags.Undefined) {
7690
context.report({ node, messageId: 'undef' });
7791
return;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// @ts-ignore
2+
declare module 'errors' {
3+
class ErrorLike {}
4+
5+
export function createError(): ErrorLike;
6+
}

packages/eslint-plugin/tests/fixtures/tsconfig.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"deprecated.ts",
1515
"mixed-enums-decl.ts",
1616
"react.tsx",
17-
"var-declaration.ts"
17+
"var-declaration.ts",
18+
"errors.ts"
1819
]
1920
}

packages/eslint-plugin/tests/rules/only-throw-error.test.ts

+68
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,56 @@ function fun<T extends Error>(t: T): void {
139139
throw t;
140140
}
141141
`,
142+
{
143+
code: `
144+
throw undefined;
145+
`,
146+
options: [
147+
{
148+
allow: [{ from: 'lib', name: 'undefined' }],
149+
allowThrowingAny: false,
150+
allowThrowingUnknown: false,
151+
},
152+
],
153+
},
154+
{
155+
code: `
156+
class CustomError implements Error {}
157+
throw new CustomError();
158+
`,
159+
options: [
160+
{
161+
allow: [{ from: 'file', name: 'CustomError' }],
162+
allowThrowingAny: false,
163+
allowThrowingUnknown: false,
164+
},
165+
],
166+
},
167+
{
168+
code: `
169+
throw new Map();
170+
`,
171+
options: [
172+
{
173+
allow: [{ from: 'lib', name: 'Map' }],
174+
allowThrowingAny: false,
175+
allowThrowingUnknown: false,
176+
},
177+
],
178+
},
179+
{
180+
code: `
181+
import { createError } from 'errors';
182+
throw createError();
183+
`,
184+
options: [
185+
{
186+
allow: [{ from: 'package', name: 'ErrorLike', package: 'errors' }],
187+
allowThrowingAny: false,
188+
allowThrowingUnknown: false,
189+
},
190+
],
191+
},
142192
],
143193
invalid: [
144194
{
@@ -485,5 +535,23 @@ function fun<T extends number>(t: T): void {
485535
},
486536
],
487537
},
538+
{
539+
code: `
540+
class UnknownError implements Error {}
541+
throw new UnknownError();
542+
`,
543+
errors: [
544+
{
545+
messageId: 'object',
546+
},
547+
],
548+
options: [
549+
{
550+
allow: [{ from: 'file', name: 'CustomError' }],
551+
allowThrowingAny: false,
552+
allowThrowingUnknown: false,
553+
},
554+
],
555+
},
488556
],
489557
});

packages/eslint-plugin/tests/schema-snapshots/only-throw-error.shot

+113
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)