Repository navigation
Allow "catch (e as Error)" instead of "catch (e: unknown)" #42596
Copy link
Copy link
Open
Labels
Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScriptAn idea for TypeScript
Description
Suggestion
TypeScript 3.x forbids type annotations in catch blocks:
try {
// ...
} catch (e: Error) { // <-- TS1996 "Catch clause variable cannot have a type annotation"
// ...
}But TypeScript 4.x relaxed this rule to accept any or unknown only:
try {
// ...
} catch (e: Error) { // <-- TS1996 "Catch clause variable type annotation must be 'any' or 'unknown' if specified"
// ...
}⭐ Suggestion: Could we relax the rule to allow Error as well?
Such a declaration would not accurately describe pathological JavaScript code.
But here's why it makes sense anyway:
- In a professional code base, thrown objects always implement the
Errorinterface. We have lint rules that enforce this. And external packages generally follow this rule as well, at least the kind we'd use for professional work. - It's wasteful for every single
catchblock to perform paranoid runtime tests forinstanceof Error. - The TypeScript compiler doesn't even support
instanceof Errorfor transpiled code. - Relaxing this rule won't cause any trouble; if some people really prefer
unknownthey can enable it via a lint rule like no-implicit-any-catch without any involvement from the compiler.
Alternate syntax
In the thread below, MickeyPhoenix suggested to use as instead of : to clarify that technically this is a type cast, while still keeping the syntax concise and intuitive:
try {
// ...
} catch (e as Error) {
// ...
}🔍 Search Terms
catch instanceof TS1996 1996
✅ Viability Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.
Reacted by AlCalzone, MickeyPhoenix, Kevin T. Coughlin, Ian Clanton-Thuon, Andrew, Corey McGregor, Renato Alencar, Sung Jeon, Shaun Saker, Paosder and 36 more
Reacted by Martin Johns, Wes Lord, hiepxanh and ExE Boss
Reacted by Patrik Valkovic
Metadata
Metadata
Assignees
Labels
Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScriptAn idea for TypeScript
Activity
lightrow commentedon Sep 15, 2021
YES, PLEASE. And ideally also a rule to bring back the TypeScript 3.x behaviour with Error being default type for catch block errors, so we don't have to specify Error type in every try-catch block
right now I'm forced to annotate all caught errors as "any" which ruins intellisense.
sanjom commentedon Sep 30, 2021
Yes! I think that would be a good trade-off for situations where we can be sure to receive an "Error" object!
ExE-Boss commentedon Oct 1, 2021
Duplicate of #20024
octogonz commentedon Oct 13, 2021
ExE Boss (@ExE-Boss) There is a slight difference between the two issues: #20024 is asking for arbitrary type annotations for catch blocks, whereas #42596 is /only/ asking for
catch (e: Error)only.The rationale given above was:
Errorinterface. We have lint rules that enforce this. And external packages generally follow this rule as well, at least the kind we'd use for professional work.catchblock to perform paranoid runtime tests forinstanceof Error.instanceof Errorfor transpiled code.unknownthey can enable it via a lint rule like no-implicit-any-catch without any involvement from the compiler.These points apply to
Errorbecause that interface describes the bare minimum properties that any sane error object should have. Whereas these points maybe would NOT be convincing for custom error interfaces.That said it does look like Daniel Rosenwasser (@DanielRosenwasser) suggested the same idea in #20024 (comment):
MickeyPhoenix commentedon Jan 20, 2022
I think that
catch (e as Error)is preferable tocatch (e: Error). The latter looks like it's something the type-checker would verify for us (which it's not), while the former looks exactly like the unsafe cast that it is.The practical result of not having a syntax like this is that people just use the default
anybehavior. Andcatch (e)is not only less visibly a type risk thancatch (e as error), it is also dangerously over-flexible as a typing:messsage, ande.stack.substr(10).Adding
catch (e as Error)will make code safer, easier to read, and more self-documenting.octogonz commentedon Jan 21, 2022
It's worth pointing out that the TypeScript code base builds with
useUnknownInCatchVariables=false.Maybe the priority for this problem would be more apparent if the compiler developers had to use their own feature. 😋
octogonz commentedon Jan 21, 2022
MickeyPhoenix This is a really great suggestion. I'm going to update the issue description to include your idea.
MickeyPhoenix commentedon Jan 21, 2022
Thanks! I wish I could take credit for it, but actually it's from Jared Russell (@jaredru)'s comment (here) as highlighted by Daniel Rosenwasser (@DanielRosenwasser) (here). I just spelled out why I think it's such a great idea. :-)
As much as I'd like to, I can't quite support the
catch (e: Error)variant, because it is an invisible type-cast. But I sure would love the explicit-cast option!octogonz commentedon Feb 11, 2022
Setting
useUnknownInCatchVariables=falseis a pretty good workaround for this problem. 👍Turns out it requires TypeScript 4.4 however (which was surprising since the problematic validation was introduced in 4.0). As soon as I added the setting to our rig, we started seeing breaks in projects that build using an older compiler. Just something to be aware of.
It would be super awesome if
useUnknownInCatchVariablescould be backported to 4.0.x-4.3.x.eduhsoto commentedon Feb 4, 2023
I tried this, without setting nothig. I don't know if it's a optimal solution. I use firebase auth.

[-]Allow "catch (e: Error)" instead of "catch (e: unknown)"[/-][+]Allow "catch (e as Error)" instead of "catch (e: unknown)"[/+]