-
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
Interface function of arity of zero gets inferred as having two different method signatures #53508
Comments
FWIW trying to do this (inferring from an overload set) in the first place is probably a very bad idea; I don't think anyone has ever done this before and it's really never been considered as a way someone might use Anyway this inference follows from the inference algorithm: It's correct for It's definitely undesirable but I don't see a way to change the rules here without breaking something else much more badly. If someone wants to put together a PR that shows otherwise, happy to review it, but I think the algorithm is broadly working as designed here. |
I've done it here. I learned about this being possible from this monster. You know how it is... never say never π€£ |
Can you explain this to me, @RyanCavanaugh? Normally, if I take a function that has no parameters (arity zero) and I try to call it with any parameters at all, that's a type error. function noArgs() {}
noArgs(); // OK
noArgs(123); // ERROR: Expected 0 arguments but got 1
noArgs.call(undefined, 123); // ERROR Expected 1 argument but got 2
noArgs(...([] as unknown[])); // ERROR A spread argument must either have a tuple type or be passed to a rest parameter.
noArgs.apply(undefined, [] as unknown[]); // Target allows only 0 element(s) but source may have more In that light, why is |
I think that what @RyanCavanaugh meant here is that: type Zero = () => void
type UnknownArgs = (...args: unknown[]) => void
type Test = Zero extends UnknownArgs ? 1 : 0 // 1
const fn: (arg: number) => void = () => {}
// this call is OK, the type expects a number, and this is satisfied
// it doesn't matter if the implementation uses this param or not
// it won't crash on the surplus of arguments
fn(100) |
OK. I think I see what's going on here. Fact 1; we all agree on arity being enforced at the call levelNobody here disagrees that this should be a type error, because a call is being made that violates the arity of this function: function noArgs() {}
noArgs(123); // ERROR: Expected 0 arguments but got 1 Fact 2; assignability does not concern itself with arityWhether it's proper to call a function with a given number of arguments is one thing, but whether it should be assignable to a type is quite another. Just because this function only cares about one argument doesn't mean it shouldn't be assignable to a type that provides for more. function reportError(errorName: string) {}
function logStuff(onError: (errorName: string, errorCode: number) => void) {
onError('bad thing', 500);
}
logStuff(reportError); // OK. The callback will only make use of the `errorName`, but that's fine. ConclusionSo given that everything is working, as designed, the upshot is that I'm just hosed unless #29732 gets implemented. Ultimately the reason that I've built this overload-inferring utility type is because I need to map over every overload to modify the return type of each. In short, what I want to accomplish is this: interface ThingDoer {
doThing(): void;
doThing(num: number): string;
doThing(str: string): bigint;
}
type AsycThingDoer = Asyncify<ThingDoer>;
// Produces:
// {
// doThing(): Promise<void>;
// doThing(num: number): Promise<string>;
// doThing(str: string): Promise<bigint>;
// }
type Asyncify<T> = // Impossible with Typescript as it is designed, currently. |
I'm not sure if this is the first test time that a test case like this is being introduced to the codebase but at the very least this PR "codifies" this as something that is being considered and one that should have some reliable semantics behind it. |
This issue has been marked as 'Not a Defect' and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
Bug Report
π Search Terms
overloads,
infer
, interfaces, arityπ Version & Regression Information
β― Playground Link
Playground link with relevant code
π» Code
π Actual behavior
When the interface in question contains a single implementation of a function, having arity zero, the
Overloads
utility type infers it as two different functions:(...args: unknown[]) => unknown
, and() => number
π Expected behavior
I expected Typescript to infer it as
() => number
alone. This would be consistent with how this utility type infers other methods having a single implementation, but arity > 0.The text was updated successfully, but these errors were encountered: