try...catch
is situational - if you want just to document an exception in JSDoc and/or are not able to handle it immediately yourself (e.g. critical error), you get in trouble with the current approach.
Also, an error is ideally self-documentary and enforces a certain behavior in the code itself - everything else is not as DRY. Code/comments can get out of sync, you might as well forget to document @throws {Error}
.
So I am not sure if an IDE or ES-lint plugin is a good idea. Instead you can create some kind of Either
data type, that enforces all consumers of a possibly throwing function (a
) to react to the error at sometime - otherwise they don't get the return value back. A simplified example:
// wrap a riscy throwing function, so that it returns a plain value ("purify it")
const tryCatch = (myRiskyFn) => {
try {
return { val: myRiskyFn() };
} catch (e) {
return { err: e };
}
}
// enforce client to handle error branch here, so we can return a well defined value back.
const valueFromEither = (either, onError) =>
"err" in either ? onError(either.err) : either.val;
// Test error case:
const a = () => { throw new Error("some error..."); };
const either1 = tryCatch(a); // throws internally
const result1 = valueFromEither(either1, err => `Oh my! ${err}`);
console.log(result1); // Oh my! Error: some error...
// Test success case:
const b = () => 42;
const either2 = tryCatch(b); // goes thru
const result2 = valueFromEither(either2, err => `Oh my! ${err}`);
console.log(`yay! ${result2}`); // yay! 42
(in the style of IO
, Either
, TaskEither
in functional programming approaches, but you can just use it on your own!)