-
Notifications
You must be signed in to change notification settings - Fork 109
Handle function overloads, perhaps by unifying signatures #180
Comments
When declaring the implementation of an overloaded function/method/ctor,
you need to provide an implementation that takes the union of all
parameters, and returns the union of all return types (and then TS trusts
you that you return the right type for the right parameter set).
Sounds like we might have to do this merge ourselves?
|
Some more instances of this problem:
Doing the merge looks like it'd generate some pretty crazy types, especially in that first case. |
Yes, the types are crazy. But OTOH, that really is the runtime type of the
method without overloads, which is probably what Closure should see, right?
|
Under the rationale of "TypeScript has already type-checked", I might just do something like /**
* @constructor
* @param {...*} args
*/
function Foo(args) {} for now. |
See for example |
From my whiteboard notes on what the generator would need to cover:
And a few open questions:
As for "TypesScript has already type-checked", that doesn't help in the "I'm still doing native JS dev" scenario, so as much fidelity as could be accomplished would be beneficial. |
If you're interested in approaching this, I think the best place to start is to just take some of the examples we have in real code (linked in this bug) and add them to the test suite. To start with, we at least shouldn't generate invalid code. |
Unless someone else has a fix in flight, I'm going to look at this over the coming week. Agree that first step is to write a reasonably comprehensive set of valid ts --> expected extern test data. |
The way the test suite works is you create a dir in |
Another interesting one. Note the differing return types. /**
* Loads the client library interface to a particular API. If a callback is not provided, a promise is returned.
* @param name The name of the API to load.
* @param version The version of the API to load.
* @return promise The promise that get's resolved after the request is finished.
*/
export function load(name: string, version: string): Promise<void>
/**
* Loads the client library interface to a particular API. The new API interface will be in the form gapi.client.api.collection.method.
* @param name The name of the API to load.
* @param version The version of the API to load
* @param callback the function that is called once the API interface is loaded
* @param url optional, the url of your app - if using Google's APIs, don't set it
*/
export function load(name: string, version: string, callback: () => any, url?: string): void; From https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/gapi/gapi.d.ts |
Another ugly case: this project has a local typings file that defines a third signature for the above "load" function. At first glance it seems there is no way to make that work, unless we have a global view of all d.ts before generating any externs. |
Evan - good references. Per your comments on a separate thread, I'm going to create the golden set of tests, with a reasonable coverage from bland to ugly, and submit that as a pr later this week. (I'm caught up in some "real" work time-sensitive stuff today/tomorrow). I'll also post some shorthand pseudocode for the alg changes I'm going to make, for comment before I get into the weeds. I agree that first and foremost this will deal with one class/interface in one file, not attempt to merge across multiple files. That can perhaps come later. On the overloaded return value example: In that particular case, since closure's standards are to not annotate a |
I think @mprobst might take a shot at this on his flight on Thursday, be sure to sync with him. |
…#180) Adds golden test code for overloaded constructor and method patterns. Includes placeholder rendering of first method when more than one signature is found for a given method name (like existing >1 constructor placeholder).
angular#180 - Adds golden test code for overloaded constructor and method patterns.
angular#180 - Groups methods by name and outputs a single method (like constructor currently does). Precursor to writing the signature merge function.
angular#180: - Added comment in externs.js for each overloaded member. - Moved method processing to after other member (typical class pattern with ctor-props-methods). - Created collection of method members in the initial members iteration, so the whole set doesn’t have to be iterated over twice.
angular#180 - Minor cleanup comments I missed in the first update.
angular#180 - Create method map in initial full member iteration.
#180 - Adds golden test code for overloaded constructor and method patterns.
This is in preparation for the next change, where it turns out that the file name matters. The test suite had no d.ts files before this change so I had to make a minor change to path handling.
#180 - Adds golden test code for overloaded constructor and method patterns.
…#211) angular#180 - Adds golden test code for overloaded constructor and method patterns.
Question on instantiating type metadata at runtime: In approaching the overloads problem, I should be able to use the existing ClosureRewriter#emitFunctionType if I can either:
If there is no easy way at runtime to dynamically build an instance of the declaration, then I'll have to perform some surgery on emitFunctionType, so as to separate the creation of the text for the tag elements (for the singular vs >1 overload variants) from the building of the tags themselves. |
I haven't yet tried creating TS AST nodes (like SignatureDeclaration). I worry it might be hard because they have offsets into the text of the source file and other parts have symbols mapped into the typechecker, but maybe you can avoid that. I think you'll likely need to take emitFunctionType apart, perhaps to accept an array of decls to merge, or perhaps to accept some intermediate data type (e.g. |
That's where I'm headed. |
Is it a strict requirement that all functions must be annotated with For example, I'm wondering if we could translate the gapi example as follows: /**
* Loads the client library interface to a particular API. If a callback is not provided, a promise is returned.
* or
* Loads the client library interface to a particular API. The new API interface will be in the form gapi.client.api.collection.method.
* @param name The name of the API to load.
* @param version The version of the API to load.
* @param opt_callback the function that is called once the API interface is loaded or undefined
* @param opt_url optional, the url of your app - if using Google's APIs, don't set it or undefined
* @return promise The promise that get's resolved after the request is finished. or undefined
* @type {function(string, string):Promise<undefined>|function(string, string, function()=, string=):undefined}
*/
function load(name, version, opt_callback, opt_url) {} In other words, we'd still follow all the rules outlined above except for "{Tx | Ty} if different types at same index", which would be replaced by the |
@butterflyhug is that a valid Closure annotation? I've never seen it done this way. |
The compiler team's documentation lists the function type. It gets used all the time for callbacks and, less frequently, for type casts. I assumed that it would be fully supported in type unions, even though I haven't seen that usage either. I just tested it. The compiler doesn't give any errors, but there's still two issues using my example with the Closure Compiler:
So, you're right, this isn't currently an option. Bummer. |
That is too bad. The other thing I'd not expect to work is when you have some |
By the way, I think this bug is mostly done. It might be worth closing it and opening bugs on any specific remaining issues. |
Calling this done. |
Uh oh!
There was an error while loading. Please reload this page.
Tsickle currently errors when generating externs from a declaration class with multiple constructors.
However, these exist in d.ts files. We need to figure out how to support it.
Example:
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/56024034ccc426af2840e90fe94043c2213dd6b4/google.visualization/google.visualization.d.ts#L238
The text was updated successfully, but these errors were encountered: