Declare multiple return types

Topics: General, Language Specification
Jan 4, 2013 at 6:42 AM

So I've been working though with TypeScript over the last 2 weeks or so, converting a pet project from JS to TS.

Aside from a few management issues (to be expected!) my experience has been amazing.

As a guy with C# experience, being able to clearly create my function overloads is amazing, I love it, and once Generics make it in, it'll be even better.  Being to have the type checking go into the function from the compiler level is great.

 

One thing that would be nice to have, is potentially the ability to define multiple possible return values.

From the compiler point of view, you couldn't infer the real return type, it would essentially be returned as <any>.

From a architecture / library creator point of view, I want to create an interface, and I want to hand out that interface to consumers of my Library, so they can work off the explicit constraints.

In my case, the library is creating a system, that's execution, can optionally be delayed by a Promise.  In addition the promise library, when, I'm using allows you to also delay it's calls, such as reduce or map, also with a promise (or returning a value).

 

A quick example case, this is from the .d.ts file I've created so far.

This is a convention interface, so the consumer of my library can create a strongly typed object.  They can choose to either return a Promise, an Array of Promises, or nothing (void). 

interface IConventionInit
{
    init(mod: IModule, facades: IModuleFacades): Promise;
}

If we could turn this around and also say, that well you can return a promise or an array of Promises, or nothing, you should be able to state that explicitly without just typing it to any.

interface IConventionInit
{
    init(mod: IModule, facades: IModuleFacades): [Promise | Promise[] | void];
}

Currently I'm using multiple interfaces to handle these scenarios, but then you have to involve extra process, and needs to be documented and understood, and users need to be trained.  This functionality would clearly state the allowed return types, to the consuming developer.

 

Thoughts?  Is this a terrible idea, something that could be of use?

Jan 4, 2013 at 8:37 AM

As a guy with C# experience you should know that the return type is not part of the function signature. And having multiple return types would lead the type system ad absurdum. How would the type system know exactly what type was returned? It couldn't. It would have to assume it's any, and then you can just use any right away.

Perhaps you should rather rethink your architecture and use better types?

Jan 4, 2013 at 5:20 PM

Perhaps I'm missing something, but the following should work:

interface IConventionInit
{
    init(mod: IModule, facades: IModuleFacades): Promise;
    init(mod: IModule, facades: IModuleFacades): Promise[];
    init(mod: IModule, facades: IModuleFacades): void;
}

So just repeat it three times with different return types;
// Peter

Jan 4, 2013 at 6:00 PM
SomebodyYouKnow wrote:

As a guy with C# experience you should know that the return type is not part of the function signature. And having multiple return types would lead the type system ad absurdum. How would the type system know exactly what type was returned? It couldn't. It would have to assume it's any, and then you can just use any right away.

Perhaps you should rather rethink your architecture and use better types?

You are correct, yes you can use any right now, but the library developer knows what possible return types are allowed, and what aren't.  This is about giving the consuming developer the ability to know exactly what types are allowed or not, and have the compiler enforce that on them.

When library side, when it sees that return value it will have no choice to refer to it as <any> since it has no idea what type it might be (it's a mixed type really).  So it's up to the library developer to use traditional JavaScript code to detect and decide on what to do with the result, not the compiler.  While the library developer is then laying the foundation for the consuming developer to say, "oh I don't have to return anything here, if I don't need to do any extra work"

 

My understanding is that TypeScript isn't about bringing C# to JavaScript, it's about bringing strong typing and tooling to JavaScript, while still retaining all of the native core functionality that JavaScript supports.  Multiple possible return values is something JavaScript supports out of the box, and those values don't always depending on the number of input parameters.  Why shouldn't TypeScript also support that possibility?

 

jbaroncom wrote:

Perhaps I'm missing something, but the following should work:

 

interface IConventionInit
{
    init(mod: IModule, facades: IModuleFacades): Promise;
    init(mod: IModule, facades: IModuleFacades): Promise[];
    init(mod: IModule, facades: IModuleFacades): void;
}

So just repeat it three times with different return types;
// Peter

 

You are correct, creating 3 separate interfaces, allows the consuming developer to pick and implement the one that he needs to implement.  This adds additional work for having to teach that developer all the different possible ways he can implement the interfaces.

If you were able to inform the developer on the one interface, that you can return type x, y, or z, and it will be handled correctly by the library.  That's all the information they need to continue on and finish work.

Jan 4, 2013 at 7:26 PM

I guess I was a bit unclear. I meant to say it is 1 interface that describes the three different flavors of the init method. The way TS does it provides the additional flexibility of changing also the parameters, not only the return type (actually you can declare "init" to be also many other things like an indexed property).

BTW I'm not convinced it is a good idea to have different return types with the same parameters. The caller now has to either check the return type or there is some "secret" not specified in the interface that determines the behavior of this method. So although possible, not sure it is desirable.

//Peter

Jan 4, 2013 at 9:51 PM

Understood, I had actually tried that (and just tried it again as a sanity check) and if you try to implement that interface, the compiler complains that the overloads are not compatible or if you skip the overloads, you get declaration incompatible.

I'll continue down the path I'm going now, maybe it may come up as something to support in the future or maybe not.  At the end of the day it's a fairly minor issue, that can be worked around.

Feb 19, 2013 at 7:26 PM
Hello,

I do not know your specific use case but can't you wrap the 'returnable' data into another class?
class ConventionData {
  public isPromise(): bool {}
  public isPromiseArray(): bool {}

  public getData(): any {}
  public setData(dat: any, type: any) {}
}
A comment by me from an issue I've opened (Suggestion: Specifying sum types)
But I had the idea to simplify it to semantic sugar, i.e. that the compiler allows a syntax mentioned above but doesn't do anything with it (treats it as 'any').

These 'annotations' would inform a reader about the types being used. Of course, this could lead some people to think that the compiler will throw a warning/error if an incompatible type is used.
I think both of our ideas actually result in 'specifying sum types'.
Feb 20, 2013 at 4:03 PM
Edited Feb 20, 2013 at 4:04 PM