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

Include error maps in the typescript libraries for web apis to give developers easy access to potential thrown exceptions #58355

Closed
6 tasks done
petermakeswebsites opened this issue Apr 29, 2024 · 7 comments
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript

Comments

@petermakeswebsites
Copy link

πŸ” Search Terms

include possible exceptions error map

βœ… Viability Checklist

⭐ Suggestion

This isn't strictly a typescript feature, but the typescript library files would be an ideal place to have it. The typescript community can get together to solve this problem and make developers lives a lot easier, and the web a lot less buggy. It's quite possible that a third-party solution would be appropriate here, but I'll put the idea out nonetheless.

Note: this feature request isn't about implementing a way where typescript can infer what error is being caught. It actually wouldn't interfere with the actual typing mechanics, it's just about the errors being available for reference in some fashion.

Background:

Part of being a experienced developer means knowing what web api / dom calls might throw and which ones might not. Unfortunately, even seasoned developers might overlook an error being thrown by a native API. This is especially important for mission critical apps, think healthcare, etc where type safety is paramount. I am actually surprised that there isn't a convention for this already. For example, querySelector will throw if the syntax isn't correct, but one might assume it would simply return null or undefined. This can create an unintentional cascade of problems that could be avoided if potential exceptions are more easily accessible. Currently, it's difficult to assess whether a particular function would throw or not. You have to reference official documentation. Having an error map would allow us to at least derive our own libraries to use for our own benefit. For example, imagine if something of the sort (forgive my terrible typescript) were possible:

// Some global error map
export type WebAPIErrorMap<T> = // .... a list of all built-in objects / classes

WebAPIErrorMap<Window> /* would be */ {
  querySelector: DOMException & {code: DOMException['SYNTAX_ERR'], name : 'SyntaxError'} // This can obviously be condensed in some way
  // ...
}

WebAPIErrorMap<Window>['querySelector'] /* would be */ DOMException & {code: DOMException['SYNTAX_ERR'], name : 'SyntaxError'}

πŸ“ƒ Motivating Example

The primary motivating example comes from an idea to allow developers to maximise type safety in JS. One idea I have is to create proxied objects around WebAPIs that use something like neverthrow's type-safe error handling. This would mean that using a try/catch block around each proxied call that could throw an error would allow the error to be returned in the result as a consumable, and a library like neverthrow could force its consumption.

Having an error map would allow the user to be able to A) know when something would throw and be forced to handle it, and B) be able to narrow down error types and handle them appropriately. For me personally this would be tremendously useful, but I believe if people got a whiff of how type safe applications could be if every API call had this kind of wrapping, there would be a whole lot less errors in the wild. This is just one idea of how these error maps might be used.

Note: I haven't given too much thought to how this exactly can be implemented and I'm apprehensive to post an example because most likely my mediocre typescript would detract from the importance of such a feature.

type Ok<T> = {value : T}
type Err<E> = {err : E}
type Result<T,E> = Ok<T> | Err<E>

// Quick example, not the global list
type WebAPIErrorMapParentNode = {
  querySelector: DOMException & {code: DOMException['SYNTAX_ERR'], name : 'SyntaxError'} // This can obviously be condensed in some way
  // ...
}

// This can be abstracted to apply to any object / function property if there's a global map
function safe<T extends ParentNode, Q extends keyof WebAPIErrorMapParentNode>(target: T, fnName : Q) :  (...args: Parameters<ParentNode[Q]> ) => Result<ReturnType<T[Q]>, Q extends keyof WebAPIErrorMapParentNode ? WebAPIErrorMapParentNode[Q] : never> {
    return function(...args : Parameters<ParentNode[Q]> ) {
      try {
        return {value: target[fnName](...args)} // Maybe this can be proxied as well
      } catch (e) {
        return {err: (e as Q extends keyof WebAPIErrorMapParentNode ? WebAPIErrorMapParentNode[Q] : never)}
      }
    }
}

const rtn = safe(document, 'querySelector')(".+-..123")
/**
 * const rtn: Result<Element | null, DOMException & {
      code: DOMException['SYNTAX_ERR'];
      name: 'SyntaxError';
  }>
 */

Playground link (note there are a couple of TS errors but the outcome still works)

As you can see, the error is available to be handled, and the type is also available.

I am aware that an actual javascript Proxy can be used which would be nicer, but the underlying idea is the same. Leverage error maps to make error handling safe.

πŸ’» Use Cases

  1. What do you want to use this for? As described above, the ability for people to create libraries that are able to use a database of error maps to handle errors in their own way. The libraries can rest on a solid foundation of typescript - staying up to date with the latest changes in specs.
  2. What shortcomings exist with current approaches? This feature is simply not possible. Not only do you have to remember which apis throw, but you also have to go to the documentation on MDN or w3c specs to find out what error types would be thrown. One can only imagine the amount of bugs currently circulating the web due to this.
  3. What workarounds are you using in the meantime? Only lengthy processes of having community devs create error maps themselves, or wrap a general error surrounding any and all function/api calls which is not pretty.
@fatcerberus
Copy link

How is this different from #57943 and/or #13219?

@petermakeswebsites
Copy link
Author

It's different from both of those because I'm not suggesting to make any changes whatsoever to the type system. My proposal simply about supplying type maps that conform to web standards so that developers can use them how they like. It's a benign addition that would just mean people who are building result-like error handling libraries can leverage a strong and trusted up-to-date backbone for reference purposes - getting potential error types given a certain type. One use case would be that it would allow type-safe libraries to create convenient proxies around web apis.

Example, typescript would supply something like this:

/**
 * Supplies an error map for a {@link ParentNode} instance
 */
type ParentNodeErrorMap = {
  querySelector: SyntaxError
  // ... all other errors
}

And then developers can build on top of those to create their own type systems, proxies, etc.

@RyanCavanaugh
Copy link
Member

I don't understand what the request on the TypeScript side is. "error map" is not a term I'm familiar with and it doesn't really turn up any search results.

@petermakeswebsites
Copy link
Author

"Error map" is just the closest way to describe what I'm trying to put forward. It's simply a utility to map a type to its associated potential error according to w3c spec. I don't have the expertise to come up with the best way to do this. All I know it requires combing through the entire w3c spec and somehow including the potential errors in some fashion that they can accessed somehow.

Example:

Section 6.4 in the selector api specifies:

If result is invalid ([SELECT], section 12), raise a SYNTAX_ERR exception ([DOM-LEVEL-3-CORE], section 1.4) and abort this algorithm.

It would be great to have a way that this error information is somehow available in typescript. This would not affecting the typing system in any way.

I was thinking of literally the simplest way, which is likely not the best way, where typescript would supply a kind of global W3CErrorMap, and a developer can go:

type querySelectorErrors = W3CErrorMap<document>['querySelector'] // would be the type of the error associated with SYNTAX_ERR

I foresee the development of type-safe proxies for standard apis.

@RyanCavanaugh
Copy link
Member

If it's not going to affect the type system in some way, it can be an out-of-band artifact that people use if they are doing this kind of thing. Expanding the scope of our project to further cover investigating all the various W3C specs to produce that document doesn't seem to be something that TS is uniquely positioned to provide.

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Out of Scope This idea sits outside of the TypeScript language design constraints labels May 1, 2024
@petermakeswebsites
Copy link
Author

That's kind of what I figured, but I thought I'd give it a shot anyway. At least to get some thought in this direction. Hopefully at least the readers can see the value in what this could provide in terms of type safety, hopefully one day have an official body backing something like this.

@typescript-bot
Copy link
Collaborator

This issue has been marked as "Out of Scope" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale May 4, 2024
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

4 participants