Why doesn't this code throw a TypeScript type error?

With interfaces defined like this:

interface IRemoteService {
  createRecord(record: RecordType): ng.IPromise<ICreateResponse<string>>;
}

interface ICreateResponse<T> {
  createdId: T;
}

      

Why doesn't the following code throw a Typescript compilation error?

class RemoteServiceMock implements IRemoteService {
  public static $inject = ["$q"];

  constructor(private $q: ng.IQService){
  }

  createRecord(record: RecordType): ng.IPromise<ICreateResponse<string>> {
    return this.$q.when({});
  }
}

      

Type $q.when

- when<T>(value: T): IPromise<T>

.

+3


source to share


2 answers


This is according to the spec. Here's your example:

interface A{
}
interface B {
  createdId: string;
}

var foo:ng.IPromise<A>;
var bar:ng.IPromise<B>;
bar = foo; // No error

      

This assignment is allowed if A is subtype B or B is subtype A. If it is not, you will receive an error message as shown below:

interface A {
  breakTypeCompat: number;
}
interface B {
  createdId: string;
}

var foo:ng.IPromise<A>;
var bar:ng.IPromise<B>;
bar = foo; // Error

      

The reason is the bivariate compatibility of function arguments. See this link for docs + reason why this is: https://github.com/Microsoft/TypeScript/wiki/Type-Compatibility#function-argument-bivariance

More details

Background

The compatibility of interface types depends on how you use them. For example. the following is not an error:



interface IPromise<T>{  
}

interface A{
}
interface B {
  createdId: string;
}

var foo:IPromise<A>;
var bar:IPromise<B>;
bar = foo; // No error

      

However, if IPromise

where to use the type parameter as a member, it will be wrong:

interface IPromise<T>{
    member:T    
}

interface A{    
}
interface B {
  createdId: string;
}

var foo:IPromise<A>;
var bar:IPromise<B>;
bar = foo; // Error

      

therefore

In defining the actual promise, we have something like:

interface IPromise<T> {
    then(successCallback: (promiseValue: T) => any): any;
}

interface A {
}
interface B {
    createdId: string;
}

var foo: IPromise<A>;
var bar: IPromise<B>;
bar = foo; // No Error

      

Since we use a T

as an argument of the function A

, and B

we will check the type by bivariance. Therefore, if A is a subset of B or B is a subset of A, they are compatible.

+3


source


I'm not sure why you are not getting the error, but I have a suggestion on how to get the warning. According to angular.d.ts when

is defined like this:

when<T>(value: IPromise<T>): IPromise<T>;
when<T>(value: T): IPromise<T>;
when(): IPromise<void>;

      



So, if you want to use when

with a lot of input, use:

return this.$q.when<ICreateResponse<string>>({});

      

+1


source







All Articles