GithubHelp home page GithubHelp logo

Comments (11)

ethanresnick avatar ethanresnick commented on April 28, 2024 2

@fatcerberus My instinct is that there are at least some cases where it’d be useful to distinguish between the different built-in error types, but I don’t think that making them structurally distinct is a requirement or blocker for this proposal. If this proposal gets any traction, I imagine there’ll be a lot of testing on real-world code before anything lands, and that real world testing should make it clearer whether making the built-in errors distinct is actually worth it.

from typescript.

fatcerberus avatar fatcerberus commented on April 28, 2024 1

Today, almost all the built-in Error types have structurally-identical definitions.

Outside of custom error subclasses (which users can make structurally distinct themselves if they need to), is there any real use case for distinguishing between, say, TypeError and ReferenceError? Unlike, say, C#, the built-in error classes in JS are very general and often fall at awkward boundaries. In other words you probably wouldn't ever write in JS

try {
    // do a thing
}
catch (e) {
    if (e instanceof TypeError) {
        console.log("invalid data was received by some function");
        // error handled, recover
    } else {
        throw e;  // not a type error, rethrow
    }
}

because you might get a RangeError instead of a TypeError due to the exact same cause (bad data passed to function, e.g.). So IMO it doesn't really matter that they're not structurally distinct.

from typescript.

DanielRosenwasser avatar DanielRosenwasser commented on April 28, 2024

Without a fully-thought out response, the way I've often alikened something like this is to #26277 ("open-ended union types"), where there is some partially-known set of constituents that you want to handle (for some definition of what "handle" is).

from typescript.

fatcerberus avatar fatcerberus commented on April 28, 2024

Open-ended unions sounds like what people are often shooting for when they try to write stuff like "foo" | "bar" | string (if not to aid with completions).

from typescript.

ethanresnick avatar ethanresnick commented on April 28, 2024

@DanielRosenwasser I hadn’t seen that issue, but this proposal would absolutely leverage open-ended union machinery if it were to exist! Obviously, that machinery alone isn’t enough to cover all the functionality here (e.g., for ErrType inference), but it's very complimentary.

from typescript.

HolgerJeromin avatar HolgerJeromin commented on April 28, 2024

I really like this proposal.

declaration file improvements should come quickly, whenever a TS-based library is recompiled and republished, because a huge amount of this error information will be inferred;

As far as I understood you want to put the inferred types automatically into generated .d.ts files (like declare function doSomething(): void throws RangeError;).
This is a new syntax so old typescript compilers will not be able to parse these files.
Not every consumer of .d.ts files are quick in upgrading, so IMO we should be able to disable this emit.
Our customers are often consuming our .d.ts files using typescript 3.9.x :-(
We guarantee this compatibility with a CI build step.
As long as we do not use new syntax (like declare function fancyGetter(name: `get${string}`): number;, new in TS4.1) in an API this is possible.

from typescript.

fatcerberus avatar fatcerberus commented on April 28, 2024

IIRC from what maintainers have said, backward compatibility for .d.ts emit is not guaranteed in general; you're expected to have a downleveling step in your toolchain if you need your declaration files to work with older TS versions than the one you're using.

from typescript.

ethanresnick avatar ethanresnick commented on April 28, 2024

@DanielRosenwasser If this proposal seems promising, what would the next step be here? Is it the type of thing where the TS team would want to see more community input before anything else? Or is the (long) previous discussion in #13219 already a signal of sufficient community demand? Are there specific issues with the proposal that I could maybe help to address? Or is it more a matter of the TS team talking internally first to figure out how/whether this would cohere with other features TS might add (like open-ended unions), how valuable error typing would be, how hard it'd be to implement, etc?

from typescript.

DanielRosenwasser avatar DanielRosenwasser commented on April 28, 2024

I think we'd have to allocate some time among the team to get a sense of everything you just listed (e.g. difficulty of implementation, feel, future-compatibility against other possible language features, etc.). Part of it is just a timing/availability thing.

from typescript.

ethanresnick avatar ethanresnick commented on April 28, 2024

Got it; makes total sense.

Whenever you and the team do have time to talk about it, I’m excited to hear what the outcome is :)

from typescript.

RyanCavanaugh avatar RyanCavanaugh commented on April 28, 2024

What we've discovered trying (multiple times!) to implement non-workarounded completion lists for open-ended unions is that the instant something doesn't have type system effects, it tends to disappear nearly immediately, or cause huge problems.

Example: having two types () => throws A (call it TA) and () => throws B (call it TB) be mutual subtypes seems fine, but it isn't. It means, for example, that given const x = e ? TA : TB, x has to be one of those types, but can't be a union, so it means TA or TB would get randomly picked. Once it gets randomly picked, then it's a huge hazard because people will inevitably try to fish out the throws type with something like type GetErr<F> = F extends (() => unknown throws infer E) ? E : never, so then type K = GetErr<typeof x> randomly gets you A or B and causes different errors to appear or not appear.

Putting in place type system features which never affect assignability is thus very dangerous, because it means that the behavior of your program becomes chaotic, or you're not allowed to use that feature in any way where it's observable, which becomes its own can of worms. Like you might just say "Oh, well, it's just illegal to write throws infer E, but that doesn't solve the problem, because you can do a trivial indirection:

const Throws<T> = () => unknown throws T;
type TA = Throws<TA>;

type Unthrows<T> = T extends Throws<infer E> ? E : never;

where now you have a situation where you can't do nominal inference of Unthrows<TA> because it would cause the illegal observation of the throws type. So now you have to have a separate system to track "type parameters where it's legal to observe them" and "type parameters where it's not legal to observe them" and come up with sensible error behavior anyone someone tries to cross that invisible line. You can keep stacking on more ad-hoc rules to try to ban this, but you'll always either end up at some extremely inconsistent (and defeatable) set of rules, or prevent the feature from being used in the way it was originally intended in the first place.

Ultimately this doesn't sound like a type system feature, for basically the same reason that type system features to create documentation descriptions doesn't exist. At the end of the day you can't add things to the type system that don't do anything because people will still find ways to observe the thing that's happening, and without some well-reasoned ordering of subtypes, that will cause a lot of unpredictable behavior.

from typescript.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.