deno_std icon indicating copy to clipboard operation
deno_std copied to clipboard

Suggestion: Add enum for `DOMException` names, similar to `HTTP_STATUS` and `METHOD` enums

Open lionel-rowe opened this issue 1 year ago • 3 comments

Is your feature request related to a problem? Please describe.

The poorly-named and overly-broad DOMException error subclass currently has no good way of distinguishing between its many possible causes. For example, when catching errors from the following, it would be useful to distinguish between AbortError (caused by aborting the controller manually) vs TimeoutError (caused by the timeout signal):

const controller = new AbortController();
onSomeEvent(() => controller.abort());
await fetch("...", {
  signal: AbortSignal.any([
    controller.signal,
    AbortSignal.timeout(TIMEOUT_MS),
  ]),
});

However, there's currently no ergonomic option for doing so:

err instanceof DOMException // true in both cases
err.name === 'TimeOutError' // false in both cases, because the capitalization should be "TimeoutError"

err.code === DOMException.TIMEOUT_ERR seems like it would be a great option, but maddeningly, the code property and its related static constants are deprecated.

Describe the solution you'd like

Something like this:

/**
 * `DOMException` error name values.
 * @see {@link https://webidl.spec.whatwg.org/#idl-DOMException-error-names | Base DOMException error names}.
 */
export const DOM_EXCEPTION_NAME = {
  /** The operation timed out. */
  TimeoutError: "TimeoutError",
  /** The operation was aborted. */
  AbortError: "AbortError",
  // ...etc
};

Edit: and/or this:

export type DomExceptionName = typeof DOM_EXCEPTION_NAME[keyof typeof DOM_EXCEPTION_NAME];
export function isDomException<T extends DomExceptionName>(x: unknown, name: T): x is DOMException & { name: T } {
    return x instanceof DOMException && x.name === name;
}

Not sure which package it'd live in though.

Describe alternatives you've considered

N/A

lionel-rowe avatar Aug 14 '24 05:08 lionel-rowe

However, there's currently no ergonomic option for doing so:

err instanceof DOMException // true in both cases
err.name === 'TimeOutError' // false in both cases, because the capitalization should be "TimeoutError"

I don't understand why someone would use err.name === "TimeOutError". They should use TimeoutError, with the correct casing. I'm not sure this is worth having an added module.

iuioiua avatar Aug 19 '24 06:08 iuioiua

I don't understand why someone would use err.name === "TimeOutError"

Because it's an equally plausible-seeming capitalization and TS doesn't provide any hints for the possible values. You could equally use "TimeoutErr", "TIMEOUT_ERR", "TimeoutEror", etc. as examples.

I'm not sure this is worth having an added module.

Possibly not, seemed useful to me but maybe not worth the overhead. One other motivating factor that's more specific to std — with the removal of DeadlineError in https://github.com/denoland/std/commit/e561d3602644585983b5db8244e996835bc75a16, there's now no ergonomic way of discriminating on the error thrown by an expired deadline.

lionel-rowe avatar Aug 19 '24 10:08 lionel-rowe

Alternative and probably more useful API:

export type DomExceptionName = "TimeoutError" | "AbortError" | ...
export function isDomException<T extends DomExceptionName>(x: unknown, name: T): x is DOMException & { name: T } {
    return x instanceof DOMException && x.name === name;
}

lionel-rowe avatar Aug 19 '24 13:08 lionel-rowe

Possibly not, seemed useful to me but maybe not worth the overhead.

Yeah. While understand the reasoning behind the suggestion. The demand must be strong enough to justify the added overhead.

One other motivating factor that's more specific to std — with the removal of DeadlineError in e561d36, there's now no ergonomic way of discriminating on the error thrown by an expired deadline.

Well, an expired deadline() will now throw a TimeoutError DOMException, as one would expect. Previously, it didn't do that.

iuioiua avatar Aug 25 '24 23:08 iuioiua

Published as a separate package: https://jsr.io/@li/is-dom-exception. I'll keep the issue open for a few more days but feel free to close if there's no demand for this in std.

lionel-rowe avatar Aug 26 '24 12:08 lionel-rowe

I don't want to push the http scope towards a dom scope, but I do think it can be useful for people that works with dom libraries.

Mainly, maintainers who are writing isomorphic code that perform dom operations, and who also need to perform the testing too while verifying the type of error.

But idk, maybe @lionel-rowe and me would be the only two potential users 😆

lowlighter avatar Sep 01 '24 22:09 lowlighter

I don't want to push the http scope towards a dom scope, but I do think it can be useful for people that works with dom libraries.

Mainly, maintainers who are writing isomorphic code that perform dom operations, and who also need to perform the testing too while verifying the type of error.

There's definitely a use case for that (whether or not in std), and as I recall my last attempt to get any of these options working satisfactorily in Deno was a disappointing failure (hopefully things have improved now, these days I just use the excellent Cheerio). But despite the name, I don't think DOMException lives under a dom scope, because many of its use cases are nothing to do with the DOM. I guess the naming is just a weird quirk of history, like XMLHttpRequest, referer, meta charset, 401 Unauthorized, etc.

lionel-rowe avatar Sep 02 '24 01:09 lionel-rowe