Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Suggestion] Multiple catch-blocks #53965

Closed
4 of 5 tasks
jeengbe opened this issue Apr 22, 2023 · 6 comments
Closed
4 of 5 tasks

[Suggestion] Multiple catch-blocks #53965

jeengbe opened this issue Apr 22, 2023 · 6 comments
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript

Comments

@jeengbe
Copy link

jeengbe commented Apr 22, 2023

Suggestion

πŸ” Search Terms

Multiple catch, catch instanceof, typed catch

βœ… 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.

πŸ“ƒ Motivating Example

try {
  JSON.parse(fs.readFileSync('save.json'));
} catch SyntaxError (err) {
  // Corrupt save file; do nothing
}
// all other (fs) errors are nothing we want to deal here with and just pass right though

Previously, this would have required a much more nested and verbose body, such as:

try {
  JSON.parse(fs.readFileSync('save.json'));
} catch (err) {
  if (err instanceof SyntaxError) {
    // Corrupt save file; do nothing
  } else {
    throw err;
  }
}

⭐ Suggestion

This suggestion extends the syntax of the catch statement by allowing one or more identifiers to restrict the type of errors that would be caught:

try {
  someFunction();
} catch ErrorA (_err) {
  console.log('Got error A')
} catch ErrorB | ErrorC (error) {
  console.log('Got error B or C', error.message)
} catch (_err) {
  console.log('Not sure what happened')
}

This would roughly translate to:

try {
  someFunction();
} catch (_e1) {
  //     ^ free emit helper variable
  if (_e1 instanceof ErrorA) {
    let _err = _e1;
    console.log('Got error A')
  } else if (_e1 instanceof ErrorB || _e1 instanceof ErrorC) {
    let error = _e1;
    console.log('Got error B or C', error.message)
  } else {
    console.log('Not sure what happened')
  }
}

To allow for multi-catch blocks, identifiers grouped with a | b | c translate to ||'ed instanceof expressions.

If no catch block without annotation is provided, the error is re-thrown:

try {
  JSON.parse(fs.readFileSync('save.json'));
} catch SyntaxError (err) {
  // Corrupt save file; do nothing
}

turns into

try {
  JSON.parse(fs.readFileSync('save.json'));
} catch (_e1) {
  if(_e1 instanceof SyntaxError) {
    // Corrupt save file; do nothing
  } else {
    throw _e1;
  }
}

No catch blocks may come after the "untyped" catch block, or else an unrecoverable syntax error is raised.


The types of the identifiers provided must satisfy the conditions for being used on the right-hand side of an instanceof expression and not be any or unknown.

If one of the provided annotations is of type any or unknown, a semantic error is raised.


For annotated catch blocks:

If not provided, the type of the variable of the catch statement is inferred to the type of the identifier used to restrict the clause.
If provided, it must be a supertype of that type or a semantic error is raised.

Type inference of the unannotated catch block (i.e. catch (err: unknown)) is not altered, hereby making the proposal fully backwards-compatible.

πŸ’» Use Cases

The goal of this proposal aligns with other languages' goals that also support multiple catch blocks:

Better code readability:

  • Different errors are "separated and decoupled more"
  • Familiar structure (other languages support multiple catch blocks)
  • One less level of indentation
  • Less if-instanceof-else boilerplate code

I would be willing to work on a PR.

@MartinJohns
Copy link
Contributor

MartinJohns commented Apr 22, 2023

Duplicate of #30830. And the viability checklist is wrongly checked.

@jeengbe jeengbe closed this as completed Apr 22, 2023
@jeengbe jeengbe closed this as not planned Won't fix, can't repro, duplicate, stale Apr 22, 2023
@jeengbe
Copy link
Author

jeengbe commented Apr 22, 2023

GitHub advises creating a new issue for this

image

@jeengbe jeengbe reopened this Apr 22, 2023
@MartinJohns
Copy link
Contributor

MartinJohns commented Apr 22, 2023

That's some automated information that may or may not align with the repositories usual workflow. I don't think re-suggesting features when they've been explicitly declined is a good approach.

The requested feature is still out of scope for TypeScript.

@jeengbe
Copy link
Author

jeengbe commented Apr 22, 2023

Thank you for your comments, @MartinJohns.

My proposal differs from #30830 insofar as it requires no type-to-runtime translation of type annotation but relies on identifiers available at runtime.

As for design goals, while this is "new syntax sugar for JS", such features do still exist (such as parameter property initialization), and similar exception may then also be made in other cases.

@MartinJohns
Copy link
Contributor

My proposal differs from #30830 insofar as it requires no type-to-runtime translation of type annotation but relies on identifiers available at runtime.

The only difference I can see is the position of the type. Otherwise it's exactly the same (except the re-throw behaviour).

such as parameter property initialization

These features stem from a dark time where the team did not have the Language Design Goals they have nowadays. Rewriting syntax like this (except for downleveling to support older ECMAScript versions) is a big no-go.

But I said my bit, I'm out.

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Out of Scope This idea sits outside of the TypeScript language design constraints labels Apr 24, 2023
@RyanCavanaugh
Copy link
Member

Everything @MartinJohns said is correct

GitHub advises creating a new issue for this

Not really germane either way, but FWIW this is GitHub Refined's UI, but GitHub itself

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

3 participants