-
Notifications
You must be signed in to change notification settings - Fork 13.1k
More explicit error message for function signature length mismatches #51457
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
More explicit error message for function signature length mismatches #51457
Conversation
|
I don't like that both types appear twice in the output; when types are long this is really cumbersome. I agree that the call/construct distinction is irrelevant here. As a starting point, we could try this (please feel free to bikeshed/iterate): Note that correctly computing the arities here is tricky since optional parameters are allowed to satisfy required ones. I recommend this testcase, which should print (2) (1), not (2) (0). function callee(n: number | undefined, m: string) { }
function caller(arg: (n?: number) => void) { }
caller(callee); |
Happy to make that change, though note that when the types are named it's a lot less obvious. For example, with type T = (a: number) => void
function takesCallback(fn: T) {
// ...
}
type T2 = (a: number, b: number) => void;
let fn: T2 = (a: number, b: number) => {};
takesCallback(fn);adopting your suggestion will mean that the error message will be whereas with the current PR it's Still, probably fine. I'll push it up (with your test) later today. |
|
@RyanCavanaugh Done. Two notes: First, your suggested message had "target" and "source" backwards from how I (and the code) think of them. That is, in Second, when
Edit: went ahead and switched the assert to a runtime test. It ought to be redundant, but it's basically free and it's on an error case anyway, so it's harmless. |
|
FWIW the source/target distinction is confusing here because of contravariance. Are we talking about the source and target of the assignment, or of the arguments (note the error as written specifically says "arguments", not "parameters")? Even knowing upfront that it's the former, it just feels weird to say that a source having more arguments than its target requires is an error condition. It'd be better if the error could somehow be written to remove this ambiguity. |
The current message says that the source requires more arguments than the target provides, and it seems like that's a pretty natural error condition to me? I'm definitely open to other wordings if you have a suggestion though. Keep in mind that this gets triggered not just in |
|
I would probably say that the source has more required parameters, since “arguments” are the values provided by the caller (hence the ambiguity—the source of those values is the target type spoken of here, and vice versa). This gets rid of the ambiguity, since it doesn’t make any conceptual sense to talk about the “source” of parameters—they are bindings, not values—except as part of a larger source/target type distinction. |
|
So "The source signature has more required parameters (2) than are provided by the target (1)." ? It seems a little odd to talk about parameters being "provided", though I guess I don't mind too much. |
|
How about just “…then the target [signature] (1)”. “Provided by” feels like unnecessary fluff at that point anyway. |
|
Hm. I feel like that makes it a harder to tell what the problem is, compared to the original error message. "this requires more things than would be provided" is clearly an error, but "this has more required things than that does" is not clearly an error, to my eyes. Happy to go whichever way the TS team prefers, though. Or maybe there's another, clearer wording, though I can't think of one. |
|
Fixed the merge conflict. Friendly ping for reviewers. |
RyanCavanaugh
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The source/target distinction is so confusing here that it even threw me off (I wrote a whole wrong comment explaining why they should be switched).
Bikeshedded with the team a bit and we figured it'd be better to mimic the concrete call mismatch error. We came up with
"Target signature provides too few arguments. Expected 2 or more, but got 1"
Overall the code/baselines look good otherwise, I think we just want the message change. Thanks!
|
@RyanCavanaugh Sounds good to me, done. |
|
@jakebailey Should I keep updating this PR to address new merge conflicts, or is that something the team will take care of when merging? I don't want to add new commits if it'll mess up the merge process. (I've spent probably 5x more time rebasing this PR than I did writing it, at this point...) |
|
It's my fault as I merged #53193 which makes our handling of diagnostic args consistent. If you don't want to solve the conflict, I'm happy to do it for you, but it should only be a single line, I think. |
|
Given this changes baselines for a common-ish error, I think I can just fix it and merge it ASAP so that future PRs fail if they don't have this new ellaboration. |
|
If you're up for taking care of the conflict and merging, please do. I can take care of it within the next couple days otherwise - doesn't look hard, I'm just swamped. Mostly I was worried that pushing a merge commit would confused the |
|
@RyanCavanaugh look good? |
Fixes #51429.
Now code like
will get an error like
instead of just the "is not assignable" part.
outdated commentary
The first commit is straightforward.
The second is less straightforward. All it's doing differentiating between "call signature" and "construct signature", which I'm only doing because other diagnostics look like they make that distinction. Differentiating requires threading through knowledge of which kind of signature is being analyzed, which is why it's a larger change. The factoring is kind of weird, but if you don't care feel free to ignore the remainder of this PR message. Or if a bare "signature" is fine instead of differentiate "call signature" from "construct signature", I can back out the second commit and use that wording instead.
The signature kind is also used to derive the earlier
incompatibleErrorReporterparameter ofcompareSignaturesRelated1. This factoring is thus a bit weird, becausekindis used both to derive a parameter and as a parameter itself. It might make more sense to deriveincompatibleReporterinside ofsignaturesRelatedTo, though that would require moving more code around, and keeps the same number of parameters since thereportIncompatibleConstructSignatureReturnfunctions close over a value (namelyreportIncompatibleError) which would need to get passed in.I'm happy with any of
compareSignaturesRelatedso that the logic derivingincompatibleReporteris inside ofcompareSignaturesRelatedJust let me know which you'd prefer.
Footnotes
as in
↩