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

Error.prototype.cause has inaccurate value type #48098

Closed
crowlKats opened this issue Mar 3, 2022 · 10 comments · Fixed by #49639
Closed

Error.prototype.cause has inaccurate value type #48098

crowlKats opened this issue Mar 3, 2022 · 10 comments · Fixed by #49639
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@crowlKats
Copy link

lib Update Request

Missing / Incorrect Definition

Error.prototype.cause's value is currently set to Error, which is inaccurate as it can accept anything, and as such should be unknown.

Sample Code

new Error("foo", { cause: "bar" });

Documentation Link

https://tc39.es/ecma262/#sec-installerrorcause

@crowlKats crowlKats changed the title Error.prototype.cause has inaccurate value Error.prototype.cause has inaccurate value type Mar 3, 2022
@DanielRosenwasser
Copy link
Member

The cause property on Error instances might need to be typed as unknown or any, but the cause property on the options bag is possibly one of those places where we'd want to take a more prescriptive stance.

@fatcerberus
Copy link

I'm not so sure about that - if options.cause is typed as Error and the project has enabled useUnknownInCatchVariables then you can't write (and note that this is the intended use case of cause):

try {
    superFoo();
}
catch (err) {
    throw new Error("superFoo failed!", { cause: err });  // type error
}

...without casting to Error, which is questionable if things are being thrown that aren't Error instances (and since TS has no checked exceptions, you can't guarantee that some dependency, deep into a call chain, isn't doing exactly that). You also can't just write catch (err: Error) {} because, again, that requires checked exceptions.

@RyanCavanaugh RyanCavanaugh added Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript labels Mar 3, 2022
@RyanCavanaugh
Copy link
Member

I sort of wonder how much we pretend that non-Error exceptions exist vs how often end-users write code on the assumption that they don't

@Jamesernator
Copy link

As suggested to me cause could be used for giving extra info for things like typing or range errors.

i.e. You might want to do something like to attach the value that caused an error:

if (value === null) {
    throw new TypeError("value should not be null under the current state", { cause: { value } });
}

if (n < 0) {
    throw new RangeError("n should not be negative", { cause: { n } });
}

@neovov
Copy link

neovov commented Mar 8, 2022

There is also some DOM errors that doesn't extends the Error interface.
For example MediaError doesn't have a name or stack properties, making it incompatible with cause.

@ljharb
Copy link
Contributor

ljharb commented Mar 19, 2022

The proposal for causes was designed very intentionally to match the type of “what can be thrown” - which is only unknown. It’s also why an absent cause is different than a present undefined.

@ljharb
Copy link
Contributor

ljharb commented Mar 19, 2022

I sort of wonder how much we pretend that non-Error exceptions exist vs how often end-users write code on the assumption that they don't

sounds like a great argument for TS to teach them that their assumption is incorrect with a helpful type error when they forget to explicitly narrow.

@conartist6
Copy link

My two cents: @ljharb says the spec has been written very carefully so that I can tell the difference between an error with no cause and a cause which has a useless value like null, which even so may really have been thrown.

I say this: whatever the spec says, anyone can still put anything in error.cause. They already do, and I don't have the luxury of assuming they were looking at the spec when they did it. If i get null as a cause, I'm just going to say that an error had no cause (no usable, meaningful cause). I don't see why I would spend many brain cells trying to figure out what someone was thinking when they wrote throw null, and if I did catch a thrown null, I would not put it in the cause of an error but would instead rethrow something like Caught unexpected primitive value `null`

@voxpelli
Copy link

People are having trouble with the types of my ponyfill as well: voxpelli/pony-cause#35 So all of the listed polyfills in the proposal repo are incompatible with the types in TS, that is quite telling.

The type of my ponyfill:

export class ErrorWithCause<T = undefined> extends Error {
    constructor(message: string, { cause }?: { cause?: T; } | undefined);
    cause: T;
}

Preferably TS would adopt the same type as I have, or else simply go with unknown as the type

@slorber
Copy link

slorber commented May 26, 2022

The problem with this is that this very idiomatic error wrapping pattern does not compile out of the box:

try {
  throw new Error('hey');
} catch (err) {
  throw new Error('ho', {cause: err});
}

CleanShot 2022-05-26 at 13 00 18@2x

Now we have to cast:

try {
  throw new Error('hey');
} catch (err) {
  throw new Error('ho', {cause: err as Error});
}

The cause property on Error instances might need to be typed as unknown or any, but the cause property on the options bag is possibly one of those places where we'd want to take a more prescriptive stance.

I understand that, but at the same time it would be great if the most idiomatic error wrapping pattern would work without too much ceremony

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
10 participants