Typescript: Allow `: { }` / `: any` type annotations on catch variables

Created on 28 Jul 2016  路  5Comments  路  Source: microsoft/TypeScript

It was pointed out in #9999 that catch variables never get narrowed because they're of type any, and you can't change their type because they're not allowed to have type annotations.

This leads to pitfalls like

try {
  // do something
} catch(e) {
  if(e instanceof MyError) {
    console.log(e.filname); // oops.
  }
}

Proposal: allow type annotations on catch variables as long as the annotated type is exactly any or { } (we can't reasonably make this an implicit any according to --noImplicitAny so that behavior would be unchanged). But now "safer" developers can write

try {
  // do something
} catch(e: { }) {
  if(e instanceof MyError) {
    console.log(e.filname); // error, property not found
  }
  console.log(e.filename); // error, forgot to narrow with a guard
}

Alternatively (or in addition to), we could just let catch variables get narrowed despite being any, but this would be a fairly odd carve-out.

Fixed Suggestion

Most helpful comment

:balloon: :tada: 10,000th issue :tada: :balloon:

All 5 comments

:balloon: :tada: 10,000th issue :tada: :balloon:

Related discussion in #8677

we could just let catch variables get narrowed despite being any, but this would be a fairly odd carve-out.

You could also see it the other way, that type guards were originally intended to work everywhere, but #1433 created a special carve-out where type guards no longer work (for pragmatic reasons). In that light, having type guards still work in the catch clause, despite the any type, is actually reducing the existing carve out.

A consideration here is discoverability. The following gives no compiler errors, so the author may mistakenly believe that TypeScript is type-checking the code when it is actually not:

try {
    foo();
}
catch (ex) {
    if (ex instanceof FooError) {
        /* recover from FooError */
        ex.foo // NOT typechecked - won't find typos, won't be picked up in refactorings
        ...
    }
    else {
        throw ex;
    }
}

It seems a bit magical and arbitrary that if we take the same code, but change catch (ex) to either catch (ex: any) or catch (ex: {}), then it _also_ compiles without errors but now provides additional type checking.

How would a user know that they need to add the annotation if the compiler doesn't complain either way? Often people don't realise there is something wrong with their code until they see a compile-time or runtime error, and with TypeScript the main benefit is to get more of the former and less of the latter.

This will be handled be #9999

Was this page helpful?
0 / 5 - 0 ratings