When annotating JavaScript sources with JSDoc comments, how do you annotate the type of the try..catch identifier?
try {
throw new Error();
} catch (whatIsMyType) {
console.error(whatIsMyType.message);
}
I'm specifically asking for the TypeScript JSDoc dialect, but an answer for the Closure Compiler dialect or even JSDoc itself would be insightful.
I tried (for TypeScript):
try { throw new Error(); } catch (/** @type {Error} */ e) {/*...*/}
try { throw new Error(); } /** @param {Error} e*/ catch (e) {/*...*/}
/** @param {Error} e*/ try { throw new Error(); } catch (e) {/*...*/}
But without success. e
has always type any
. What would work is
try { throw new Error(); } catch (_e) {
/** @type {Error} */
var e = _e;
// ...
}
And the additional variable would be optimized away by closure compilers advanced mode, but I find that cumbersome and not optimal from a performance perspective (in a dev build) and hope there is a better way (i.e. one where I don't have to create an artificial variable just to annotate the right type).
try {throw new Error();} catch (/** @type {Error}*/whatIsMyType) {
console.error(whatIsMyType.message);
}
Is valid according to Closure Compiler.
I don't write much typescript, but I've poked around at a few sources and mostly don't see annotations at the catch
level. The few I did see looked like this;
try { throw new Error(); } catch (e: Error) {}
Update:
I think TypeScript has it right in refusing to guarantee a type for the check
block. You can throw anything (intentionally or otherwise) within a try
block so the compiler can't assure the catch is caught with the right type. In a related answer the solution is that you should check the type in the catch
:
try {
throw new CustomError();
}
catch (err) {
console.log('bing');
if (err instanceof CustomError) {
console.log(err.aPropThatIndeedExistsInCustomError); //works
console.log(err.aPropThatDoesNotExistInCustomError); //error as expected
} else {
console.log(err); // this could still happen
}
}
And I (and Robert Martin) encourage this style of type checking even with strong types.
Update 2
I've re-written the example from above into Closure Compiler syntax, and I believe the point remains valid. Even if Closure lets you do the definition from the first example, you probably don't want to (or at least, not only that):
class CustomError extends Error {
constructor() {
super();
/** @type {string} */
this.aPropThatIndeedExistsInCustomError = '';
throw new Error('Not so fast!'); // The evil part is here
}
}
try {
throw new CustomError();
}
catch (/** @type {CustomError} */err) {
console.log('bing');
if (err instanceof CustomError) {
console.log(err.aPropThatIndeedExistsInCustomError); //works
console.log(err.aPropThatDoesNotExistInCustomError); //error as expected
} else {
console.log(err); // this could still happen
}
}