-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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 messages should place most relevant information first. #29759
Comments
Tagging @DanielRosenwasser for thoughts here. I'm curious if there is a specific reason why we do things this way? It seems like a bunch of effort was put into extracting out some really good information to tell the user. But that good information is buried after the really crufty info which, while occasionally useful, seems strange to place front and center. |
Sometimes inside-out is the best error, sometimes outside-in is the best error. It depends on whether your error is because the type "isn't even close" (i.e. you have the completely wrong kind of object), or if there's something "subtly wrong" (i.e. you are off by one property spelling or type). Consider this code: // Library code
type Flippy<T> = T extends string ? number : object;
class Alpha<T> {
getBar() {
return {
doSomething() {
return {
another: null as Flippy<T>
}
}
}
}
}
class Beta<T> {
getBar() {
return {
doSomething() {
return {
another: null as Flippy<T>
}
}
}
}
}
// User code
const a: Alpha<string> = new Beta<boolean>(); The error message here is:
The last 7 lines of that error message are not really relevant (it's not really the error the developer is making, just an explanation of why the assignment is an error), and arguably only the first line is needed for the user to know what's gone wrong. Displaying the inner message first here looks like TS has lost its mind:
|
Well, for a variable, it would be very confusing if you dove deep into the structure of the type and never explained how the mismatch occurred. declare var x: { a: { b: { c: { d: number } } } };
declare var y: { a: { b: { c: { d: string } } } };
x = y; It'd be weird to get an error like
even if it looks less scary than
But when we already try to do this when we have the syntax available, we're able to error exactly on the appropriate declaration. declare var x: { a: { b: { c: { d: number } } } };
x = { a: { b: { c: { d: "" } } } };
// ~ Error: Type 'string' is not assignable to type 'number'. It's only on excess property checks (like here) that we don't currently, and that's because we don't try to do it as part of the syntactic walk that @weswigham implemented to elaborate on the most specific error location. |
I suppose we could just set a bit to say "don't try to elaborate any further" when excess property checks are issued. |
Note: i'm not proposing stripping out the "path" part of the error. Just that it feels as if the innermost message is sometimes far more appropriate on the outside level. I mean, just look at that useless vscode message :) |
How'd you get in a state where the excess property check wasn't the top-level error? Having a hard time reproducing the OP |
Note: i would say that hte error here is good because the "type not assignable" message is non-complex. And, by 'non-complex' i mean: there is a good named type that can be presented to the user. In this case, saying "Foo is not assignable to Bar" is nice and clear. And the path then leads to an explanation why. When the message is:
(or even worse at times). It seems like this may be about having a weighed strategy depending on what sort of message you'd print. |
let x: { a: string, b: number } = {
a: "",
b: 10,
c: 20
} |
To be clear, the span is exact (we literally override the original span) but the exact elaboration comes last. |
It could be:
That's not scary to me :). It explains what's going on to me in the first line. Part of the assignment deep inside isn't compatible. And if that information isn't clear enough, i can walk down the path to find out which part if is complaining about. |
But it's not really nested like the OP shows let x: { q: { m: { t: { a: string, b: number } } } } = {
q: {
m: {
t: {
a: "",
b: 10,
c: 20
}
}
}
};
|
@RyanCavanaugh Are you asking for a repro for the OP i posted? |
I just want a multi-level error message originating in an excess property check. That seems like a specific scenario to address by itself. |
Also Cyrus what version are you on? We might've just gotten better at this. |
package.json says |
... I should just walk over to Cyrus's office? |
Hurrdurr. Me smart. Me also on 3.2.2 Where are you now? Our current office is downtown :D |
Didn't realize you moved! I'm still over by the cat bookstore. |
So this isn't a full repro. But this is basically what we have; export class FargateService {
constructor(name: string, args: FargateServiceArgs) {
}
}
export interface FargateServiceArgs {
taskDefinitionArgs?: FargateTaskDefinitionArgs;
// cutting out a lot
}
export interface FargateTaskDefinitionArgs {
container?: Container;
containers?: Record<string, Container>;
// cutting out a lot
}
export interface Container {
// Properties from aws.ecs.ContainerDefinition
image?: pulumi.Input<string>;
memory?: pulumi.Input<number>;
environment?: pulumi.Input<KeyValuePair[]>;
// cutting out a lot
}
// And then we're constructing like so
const nginx = new awsx.ecs.FargateService("nginx", {
taskDefinitionArgs: {
containers: {
nginx: {
image: "nginx",
memory: 128,
enviroment: 128,
},
},
},
});
// Unfortunate, Input is a pretty complex type on it's own... but maybe this is enough to get by? |
Check out #29760. |
Would love to know whether #33361 (PR at #33473) mostly fixes the issue @CyrusNajmabadi @lukehoban. |
My question is why the error messages in TypeScript can not be inverted... so that if
to take the error from the OP it would be something like this:
|
As noted above, if we inverted errors, then the other ~half of the time, you'd have the same problem as you have now. The "correct" end of the error depends on the nature of the problem, which the computer doesn't really have a way of knowing since it doesn't know what your intent was. |
Can it be a flag (in the IDE settings) I am using the ubiquitous VSCode |
Here's an actual example of an error message that can go wrong in our library when mispelling a property when creating an object literal:
The funny thing here is that the final parts of the error message are superb. Namely:
However, the actual output is quite cluttered and hard to glean the information from. This is esp. true in an ide setting where one sees something like this:
This view is particularly problematic due to the wrapping and wall-of-goop nature of this type of error.
My suggestion would be to invert the information being provided by errors. Give the most specific and directly impactful information first (i.e.
Object literal may only specify known properties, but 'enviroment' does not exist in type 'Container'. Did you mean to write 'environment'?
), and then follow that up with all the extra details that can be used to dive deeper into things when that isn't clear enough.The text was updated successfully, but these errors were encountered: