-
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
Call signatures of union types #7294
Comments
|
This is currently by design because we don't synthesize an intersectional call signature when getting the members of a union type -- only call signatures which are identical appear on the unioned type. To make this work, we'd need some plausible algorithm that takes two sets of signatures and produces one (or many?) new signatures that are substitutes for the original. interface Alpha {
(x: string): void;
(y: number, z: string): void;
}
interface Beta {
(...args: Array<number|string>): boolean;
}
interface Gamma {
(y: string|number, z: any): string;
}
let ab: Alpha | Beta;
let ac: Alpha | Gamma;
let bc: Beta | Gamma;
// What arguments can I invoke ab, ac, and bc with? |
@DickvdBrink getting an error (albeit a different one) the way you laid out your example is a completely expected thing:
|
@Aleksey-Bykov, you are correct - I made a mistake when creating the example - updated it. |
@RyanCavanaugh First, "align" all signatures so parameters can be compared on an individual basis. If any signatures contain rest parameters, pad all signatures with rest parameters of type Taking your first example (
Then, you apply this same algorithm again with the remaining signature and the next argument, until you've eventually exhausted all parameters (the rest parameter is treated as a single array parameter). Note that your uncertainty about what is being returned and the constraints on what you have to pass both grow very rapidly with the number of parameters and overloads. While it seems to me that this is sound in the general case, it is likely to only be useful for simple function signatures. |
Different code, related issue: export type URI<K extends RouteParams> = string;
export interface RouteParams {
[key: string]: (string | number | boolean)
}
export interface Document {
[key: string]: (string | number | boolean)
}
/**
* Create a URI from a document properties
* @param the props to build the URI from
* @return the URI
*/
export type RouteCreator<K extends RouteParams> = (props: K) => string;
/**
* Parses a URI and returns the props
* @param uri the URI to parse
* @return the params parsed from URI
*/
export type RouteParser<K extends RouteParams> = (uri: string) => K;
export type Route<T extends RouteParams> = RouteParser<T> | RouteCreator<T>;
/**
* Creates a Route which is a function that either parse or stringify object/string
* @param route the route uri
* @return the Route
*/
export type RouteFactory<K extends RouteParams> = (route: string) => Route<K>;
export interface DocURI<K extends RouteParams> {
route: RouteFactory<K>;
} import {DocURI, Document, RouteParams, URI, RouteFactory} from './Definitions';
const docuri = require('docuri');
function getRoute <T extends Document> (): DocURI<T> {
return (docuri as DocURI<T>);
}
...
const artistURI = getRoute<ArtistParams>().route('artist/name');
const parsed = artistURI(album.artist); // Cannot invoke an expression whose type lacks a call signature. Type 'Route<ArtistParams>' has no compatible call signatures. |
I just ran into this with a situation like this: let promise: Promise<boolean> | PromiseLike<boolean> = this.getPromise();
promise.then((result) {
}); The getPromise has the ability to return either a Promise or PromiseLike, of which both interfaces support the Just thought this was another useful use case for this functionality which was worth sharing. |
if you're not going to have type let promise: PromiseLike<boolean> = this.getPromise(); // returns Promise<boolean> | PromiseLike<boolean>
promise.then((result) {
}); |
To add to this issue, I just saw this rear it's ugly head while working on the definition for the 'q' promise library. We have this definition:
With this compilation test to make sure all our types are working:
Everything compiles fine, however, TSLint is saying that we can combine the function signature since the only thing that changes is the input. Sounds good, less code, so I modify my 'all' function definition for the different types:
But when I do so, the same test as above is now giving me an error:
In the meantime, I can work around it easily by removing the TSLint rule and keeping it as it was, but I'm curious as to why typescript is having problems deciphering the type based on the signature since it works when using overloaded functions. |
This is still an issue with TS >3.3 when you cannot change the function signature for 'aligning' because they are defined in an external lib. For instance with Mongoose:
|
This is a must-have for mapping over method-chained / fluent interfaces. |
Is this the same case and would be closed as a duplicate? interface Fizz {
id: number;
fizz: string;
}
interface Buzz {
id: number;
buzz: string;
}
([] as Fizz[] | Buzz[]).map(item => item.id); |
I came across this issue when trying to choose between graphql response and default initial data for a form. Each come with their own data format, due to the one being an API response. type CompoundType = Campaign_result | Campaign
const initialData: CompoundType = props.campaign || emptyCampaign full snippet and codesandbox example here issue@33591 |
I ran into this exact problem. Is it the same case? |
|
Since this has been fixed, can you reopen #20190 ? |
TypeScript Version: 1.8.4
Code
Expected behavior:
I was hoping everything would go fine (which is the case when I only use one interface in the function
test
Actual behavior:
I get an error: "Cannot invoke an expression whose type lacks a call signature". Is this by design?
The text was updated successfully, but these errors were encountered: