TSC 0.9.5 and incompatible function types

Topics: General
Dec 5, 2013 at 6:38 PM
This sample code won't compile on 0.9.5:
interface JQueryPromise<T> {
   done(...doneCallbacks: { (value: T, ...args: any[]): void }[]): JQueryPromise<T>;
}

var test: JQueryPromise<number>;

test.done((a, b) => {});
Gives:
Call signatures of types '(a: number, b: any) => void' and '(value: number, ...args: any[]) => void' are incompatible:
        Call signature expects 1 or fewer parameters.
Is this a bug or by design?
Developer
Dec 5, 2013 at 9:10 PM
This is by design. The callbacks for JQueryPromise<T>.done are saying that they must have a single required parameter and then any number of optional parameters. But you've passed it an implementation for the callback that has 2 required parameters. Now a valid invocation of a done callback can be an invalid invocation of the provided implementation of a done callback. This wasn't being enforced correctly in previous versions of TypeScript. Consider:
interface JQueryPromise<T> {
    done(...doneCallbacks: { (value: T, ...args: any[]): void }[]): JQueryPromise<T>;
}

class MyPromise<T> implements JQueryPromise<T> {
    constructor(public data: T) { }
    done(...doneCallbacks: { (value: T, ...args: any[]): void }[]): JQueryPromise<T> {
        for (var i = 0; i < doneCallbacks.length; i++) {
            doneCallbacks[i](this.data); // myArg now gets invoked with no value for b, null reference runtime error ensues
        }
        return this;
    }
}

var test: JQueryPromise<number> = new MyPromise(1);

var myArg = (a, b) => {
    console.log(b.someStuff);
    return new MyPromise(a);
};
test.done(myArg);
Dec 6, 2013 at 1:46 PM
But even with the correct parameters, the value for the callback can be null. Anyone that calls a member in an object without checking for the instance is just asking for an error. Doesn't make much sense to restrict this type inference because of this.

After what you said, I made the second parameter optional and then it compiled fine:
interface JQueryPromise<T> {
   done(...doneCallbacks: { (value: T, ...args: any[]): void }[]): JQueryPromise<T>;
}

var test: JQueryPromise<number>;

test.done((a, b?) => {});
The problem is that it doesn't make sense for code that really accepts 2 values as the parameter should not be optional.

The ideal would be to have something like Func<T> in .NET, like:
interface JQueryPromise1<T1>         { done(arg1: T1): void }
interface JQueryPromise1<T1, T2>     { done(arg1: T1, arg2: T2): void }
interface JQueryPromise1<T1, T2, T3> { done(arg1: T1, arg2: T2, arg3: T3): void }
This way, we could define the method correctly like:
foo() : JQueryPromise<string>
bar(): JQueryPromise<number, number>
But TypeScript only sees the third declaration.

Is there any way to map the jquery promise correctly in typescript and allow type inference on promise methods?
Dec 9, 2013 at 12:59 PM
So, is there any way to make types flow to jquery promise methods correctly in 0.9.5?