-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Union of function signatures cannot be invoked because it lacks a call signature #4612
Comments
I guess it has to do with the fact that the union type doesn't contain call signatures unless the signature parameters match exactly in all constituents types 3.11.1. So does that mean the bug was in 1.5.3 to allow it to compile in the first place? |
This a result from removing the aggressive subtype reduction that was in 1.5.* (see #3823). Now we are not reducing to subtypes, so the type still contain the two signatures. at time when the call resolution happen 3.11.1 takes effect, and no call signatures are found. This is a breaking change from 1.5.3 (will add it to the docs). Also related to #3823 |
Does not reducing to a subtype with one signature help prevent any errors? And is there a way to make this work with 1.6 while still keeping the union type? |
You could use call, apply or bind. I know it´s very ugly but It works.
|
Yeah. Splitting into two handlers is cleaner, so I'll go with that. |
@Arnavion, the aggressive subtype reduction would causes cause these errors to disappear, but it also caused loss of information from the union type. the fix was to keep the union information as long as possible. Subtype reduction now is only happening on the lever of operators like conditional and Or (see #3823). in this sense something like: var foo1: ((arg: string) => void)
var foo2: ((arg: any) => void);
var foo = foo1 || foo2;
foo(null); // works |
Looks like we also get this error when both types are derived from the same base class and we try calling a method of the base class. Is that expected as well?
|
@drarmstr, this should not be an error. i think there is something else going on. also this is an old issue. please file a new one with more information about your code and the version of the compiler you are using. |
@drarmstr that code doesn't issue an error when I compile with the latest TypeScript |
Yeah, the scenario was from a much more complicated code base. If I can get a simpler test case to reproduce then I'll submit a new issue. I switched to using an interface for the common methods, though, and it's been working for me.
|
Hmmm. A scenario like following still throws this error in 1.8.7, which doesn't seem like it should:
However if making it more permissive:
or restricted:
fixes the error. |
It seems this is still an issue in TS 2.4.2 export type MyControllerHandler = (e:MyValueEvent)=>void;
export type MyPatchHandler = (e: MyPatchEvent)=>void;
export type MyHandler = MyPatchHandler | MyControllerHandler;
declare const onChange: MyHandler;
onChange({}as any); // Error:(42, 17) TS2349:Cannot invoke an expression whose type lacks a call signature. Type 'MyHandler' has no compatible call signatures. This fixes the error: export type MyHandler = (e:MyValueEvent | MyPatchEvent)=>void; |
I am running into this in 2.6.2, it seems odd to me that this doesn't work. Is this working as intended? Here's pretty simple example: class TestClass {
public foo(x: string | number) {
}
}
class TestClass2 {
public foo(x: string) {
}
}
const bar: (TestClass | TestClass2) = new TestClass();
bar.foo("baz"); // Cannot invoke an expression whose type lacks a call signature.
// Type '((x: string | number) => void) |
// ((x: string) => void)' has no compatible call signatures. I am getting around it currently by casting to an interface with the "correct" union. interface FooShim {
foo(x: string | number): void;
}
(bar as FooShim).foo("baz"); |
I have this issue in 2.8.1, those workaround doesn't apply for me because I would like to overload a function. Example of my overload: type A = (b: boolean) => void;
type B = (a: string, b?: boolean) => void;
interface Props {
handler: A | B
}
(bar as Props).handler(false); //TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'A | B' has no compatible call signatures. |
@dkoprowski You want |
Reduced test case:
error TS2349: Cannot invoke an expression whose type lacks a call signature.
null is assignable to both string and any so it should compile.TypeError: Cannot read property 'flags' of undefined
in playground even though it compiles fine with 1.5.3. I didn't try quickinfo on 1.6((arg: string) => void) | ((arg: number) => void);
(number instead of any in the second signature) then both 1.5.3 and 1.6 give that error, even though again null is assignable to both.For motivation, the original code is https://github.com/Arnavion/libjass/blob/6606413/src/utility/promise.ts#L363 (the error is on handler). It's an implementation of the ES6 promise spec, specifically http://www.ecma-international.org/ecma-262/6.0/#sec-promisereactionjob - handler would be either the fulfilled callback or rejected callback and the argument passed to it would be either the resolution value or the rejection reason accordingly, hence its signature.
(I understand it would be more type-safe to have separate handlers for the two cases with one signature each from the union, but that complicates the implementation slightly.)
The text was updated successfully, but these errors were encountered: