3

Is there a "best practice" sort of way how one would mark a function in TypeScript with the information that this function throws an error?

In Java one would annotate the function's signature with "throws XYError". This does not work with TypeScript.

I understand that it is not needed for the code to run but as far as I am concerned it is cleaner code when the function signature already tells me such information.

Any reasoned tips on how you guys deal with that situation are appreciated.

Simeon
  • 748
  • 1
  • 9
  • 26
  • 3
    There's nothing in the language for that, unfortunately. I opened an issue for it: [`throws` clause and typed catch clause](https://github.com/Microsoft/TypeScript/issues/13219). You are welcomed to comment and vote on it. – Nitzan Tomer Jun 27 '17 at 12:43

1 Answers1

-3

Your function should return a Promise. This is the natural way of representing the eventual completion or failure of an asynchronous operation.

This is for asynchronous functions only. And in my opinion, the best practice is to not throw exceptions from synchronous functions at all.

  • accessing files, databases, network services - these should be asynchronous

  • argument is out of range - this traditionally is not an error in javascript: pop() from empty array returns undefined, substring() with invalid range returns empty string, and this is a good thing IMO - it results in much cleaner code in the caller

  • argument is null - compile with --strictNullChecks on, then you can rely on callers never passing null

  • stack overflow, out of memory - these are not thrown explicitly, there is no point in declaring them because any function may throw them (in Java, these are runtime exceptions and are not checked too)

Is there anything else left that warrants throwing an exception from synchronous function? If it is, I think it's too rare to have an explicit support in the language.

artem
  • 46,476
  • 8
  • 74
  • 78
  • 2
    Where did the OP said anything about "asynchronous"? – Nitzan Tomer Jun 27 '17 at 13:56
  • @artem your answer is a valuable contribution regarding my question even though I did not pay attention to the difference between asynchronous and synchronous functions. – Simeon Jun 27 '17 at 14:40
  • To me Promises as a return seems far more complex to read than a Java-like function Signature. Also I do think that handing over implicit problems/errors to the calling function instead of throwing errors does NOT result in cleaner caller code but the opposite. If one stops thinking about errors as an unwanted obstacle one has to deal with but looks at them as a valuable information, well managed errors will become your friend. The caller can take care of the normal logic without null-checking and similar things. All it has to do is catching the errors that it should know about. – Simeon Jun 27 '17 at 14:41
  • My point is if an error is considered a 'valuable information', it better represented as a normal return data type - typescript has union types that fit perfectly here. Exceptions are, well, for exceptional errors. – artem Jun 27 '17 at 14:45
  • 1
    Why use a if/else (with type guards) to make sense of what was returned, if the language lets you throw and then use try/catch? – Nitzan Tomer Jun 27 '17 at 14:54
  • @NitzanTomer - there is very simple practical reason to avoid using exceptions in normal flow. If your application has a bug that results in `NumberFormatException`, for example, then you want to set ''break on all exceptions" in debugger and expect it to show you the exact place where the bug happens. In reality, it stops hundreds of times on `NumberFormatException` thrown by some request parsing library in its normal flow, before it gets to your exception. Happens all the time in java. – artem Jun 27 '17 at 15:12
  • Why would I ever want to ''break on all exceptions"? Makes no sense to me. I'd just put a breakpoint inside the `catch` clause. Throwing errors is a feature of the language and it makes perfect sense to use when you want to convey that "something went wrong". – Nitzan Tomer Jun 27 '17 at 15:15
  • ''break on all exceptions" is the way to find that catch clause. The application is big, is written by a large team, the bug is triggered by particular sequence of actions in UI and you have only rough idea which part of code is executed, (the application is big and no one can be expected to remember all the details), and there are many catch clauses in that part. "break on all exceptions" is a sure way of finding that catch clause immediately, but only if no one uses exceptions in normal flow. – artem Jun 27 '17 at 15:23
  • If you use exceptions in a normal way then you should be able to figure out where the error was thrown. That can be done using the type of the error, by the message attached to it and by the stack trace. Any feature can be abused, but if you use it properly then it is very beneficial. – Nitzan Tomer Jun 27 '17 at 15:31
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/147740/discussion-between-artem-and-nitzan-tomer). – artem Jun 27 '17 at 15:49