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>
.
source to share
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.
source to share
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>>({});
source to share