Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript properties returning a promise - Get/Set accessors must have the same type

Why does TypeScript enforce Get/Set accessors to have the same type? Let's say I want to have a property which returns a promise.

module App {
    export interface MyInterface {
        foo: ng.IPromise<IStuff>;
    }

    export interface IStuff {
        bar: string;
        baz: number;
    }

    class MyClass implements MyInterface {
        private _fooDeferred: ng.IDeferred<IStuff>;

        constructor(private $q: ng.IQService) {
            this._fooDeferred = this.$q.defer();
        }

        get foo(): ng.IPromise<IStuff> {
            return this._fooDeferred.promise;
        }

        set foo(value: IStuff) {
            this._fooDeferred.resolve(value);
        }
    }
}

'Get' and 'Set' accessor must have the same type will be the error message coming from TypeScript.

The fix would be to type the accessors to any, but then we are losing the advantages of static typing, and might as well just write JS.

        get foo(): any {
            return this._fooDeferred.promise;
        }

        set foo(value: any) {
            this._fooDeferred.resolve(value);
        }
like image 332
myartsev Avatar asked Feb 04 '15 19:02

myartsev


1 Answers

This sounds like a perfect opportunity to use a union type (TypeScript 1.4 or above) - example taken from this blog post:

type StringPromise = string | ng.IPromise<string>;

module App {
    export interface MyInterface {
        foo: ng.IPromise<string>;
    }

    class MyClass implements MyInterface {
        private _fooDeferred: ng.IDeferred<string>;

        constructor(private $q: ng.IQService) {
            this._fooDeferred = this.$q.defer();
        }

        get foo(): StringPromise {
            return this._fooDeferred.promise;
        }

        set foo(value: StringPromise) {
            this._fooDeferred.resolve(value);
        }
    }
}

Notes:

  • You will need to use type guards when you want to use a specific type from the union type
  • You may need to use type assertions in some cases

Type Guard

Here is an example of a type guard

if (typeof value === 'string') {
    // the type of value inside this if statement is
    // string, rather than StringPromise
} else {
    // the type of value inside this else statement is
    // ng.IPromise<string>, rather than StringPromise
}

Type Assertion

If needed, you can assert types like this:

var prom = <string> value;
like image 170
Fenton Avatar answered Nov 08 '22 08:11

Fenton