I've recently added eslint
to my Typescript codebase.
By default, it enables the @typescript-eslint/no-unsafe-member-access
.
And all of sudden, I'm getting tons of lint errors on my catch blocks.
Is there a good workaround for this?
Typescript does not allow me to type it as Error
directly from the catch statement like catch(err: Error)
.
I don't want to disable the rule pletely, neither I want to add eslint-disable
on every catch(err)
block.
I've recently added eslint
to my Typescript codebase.
By default, it enables the @typescript-eslint/no-unsafe-member-access
.
And all of sudden, I'm getting tons of lint errors on my catch blocks.
Is there a good workaround for this?
Typescript does not allow me to type it as Error
directly from the catch statement like catch(err: Error)
.
I don't want to disable the rule pletely, neither I want to add eslint-disable
on every catch(err)
block.
-
The
err
truly can be anything, which is a problem. You can type it asunknown
to be safe and then narrow it down. But for me, in this situation I usually just disable type-checking and logerror.message
iferror
is an object – CertainPerformance Commented Mar 3, 2021 at 17:59 - @CertainPerformance thank you. Would you write an answer with a plete example of your suggestion? – cbdeveloper Commented Mar 3, 2021 at 18:01
- I don't consider it to be a remotely elegant solution, there might be something better – CertainPerformance Commented Mar 3, 2021 at 18:02
-
@CertainPerformance Yeah, I've thought of some ways to handle it. But they all involve reassigning
err
to change its type and that feels repetitive and unnecessary. Let's see if someone es up with some better solution to this problem. – cbdeveloper Commented Mar 3, 2021 at 18:04
3 Answers
Reset to default 7There are various uncertainties in the try
block, and JavaScript can throw not just an Error object, but even a string
, or even null
or undefined
. We can use instanceof-narrowing to avoid such a warning
try {
...
} catch(e) {
if (e instanceof Error /*CustomError*/) {
console.log(e.message)
}
}
This is terribly ugly code, but...
// before
try {
/*...*/
} catch (err) {
if (err.name == 'AbortError') {
/*...*/
}
}
// after
try {
/*...*/
} catch (err) {
if ((err as {name?: string})?.name == 'AbortError') {
/*...*/
}
}
If you are using interfaces or types, instanceof
will not work. (Correct me if I'm wrong.) There are other ways to use it directly, but I usually use it with classes in Typescript.
If you don't have access to something for checking instanceof
, you can add a type guard. There are a few ways to do this, but this one worked recently:
interface IErrorLike {
name: string;
}
function isErrorLike(candidate: any): candidate is IErrorLike {
return ('name' in candidate);
}
// and in your other code block
try {
//...
}
catch (err: any) {
if (isErrorLike(err)) {
console.log(err.name);
}
}
Up until recently, I also relied on null propagation but eslint doesn't like that, even in my type guard. I prefer to see this format of the type guard, but it gave me the same eslint error as your original question.
function isErrorLike(candidate: any): candidate is IErrorLike {
return Boolean(candidate?.name);
}
I didn't dig enough to find out if it's due to newer eslint rules or if I just disable the ones I don't like-- I tend to use just the built in TS validations in my personal projects. There are very few lint rules I've seen that aren't just preferred styles.