Skip to content

Using void in generic overloads (changed between 1.0.3 and 1.1) #939

@poelstra

Description

@poelstra

The following code used to work in TS <= 1.0.3, but stopped working in TS 1.1.

interface Promise<T> {
    /* ... */
}

interface Deferred<T> {
    resolve: (value: T) => void;
    reject: (error: Error) => void;
    promise: Promise<T>;
}

interface VoidDeferred extends Deferred<void> {
    resolve: (value?: void) => void;
}

function makeDeferred<T extends void>(): VoidDeferred;
function makeDeferred<T>(): Deferred<T>;
function makeDeferred<T>(): Deferred<T> {
    // Dummy code
    return {
        resolve: function () { },
        reject: function () { },
        promise: null
    };
}

var normalDeferred = makeDeferred<number>(); // this is line 26
normalDeferred.resolve(3);

var voidDeferred = makeDeferred<void>();
voidDeferred.resolve(); // Note: no need to pass an 'undefined' value

The idea is that the T extends void overload of makeDeferred() returns a VoidDeferred, on which I can call resolve() without an argument. For non-void Deferred's, I do have to pass an argument to resolve().

When running it against the latest master, I get the following:

$ node ../TypeScript/built/local/tsc.js -m commonjs promise.ts
promise.ts(26,35): error TS2344: Type 'number' does not satisfy the constraint 'void'.
promise.ts(27,24): error TS2345: Argument of type 'number' is not assignable to parameter of type 'void'.

Apparently, it's trying to match 'number' to the 'void' type, which fails, but it doesn't try to use the more generic overload that follows (as it did in 1.0.3).
Changing the order of the overloads doesn't help, as the returned type then becomes a 'normal' Deferred (not a VoidDeferred), which requires passing an argument to resolve(), e.g. resolve(undefined).

Is there a better way of doing this?
Ideally even without having that VoidDeferred type?
I'm thinking of something like a 'specialization' of the interface just when T happens to be void, or maybe even that the compiler allows ommitting the argument if its type is void?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions