为什么此代码不会导致TypeScript类型错误?

时间:2015-06-03 15:18:48

标签: angularjs typescript typescript1.5

接口定义如下:

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

interface ICreateResponse<T> {
  createdId: T;
}

为什么以下代码不会导致Typescript编译错误?

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

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

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

$q.when的类型为when<T>(value: T): IPromise<T>

2 个答案:

答案 0 :(得分:3)

这是根据规范。以下是您简化的示例:

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

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

如果A是B的子类型或B是A的子类型,则允许此分配。如果不是这种情况,您将收到如下所示的错误:

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

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

原因是函数参数的双变量兼容性。请参阅此链接了解文档及其原因:https://github.com/Microsoft/TypeScript/wiki/Type-Compatibility#function-argument-bivariance

详细

背景

接口的类型兼容性取决于您如何使用它们。例如。以下不是错误:

interface IPromise<T>{  
}

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

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

但是如果IPromise将type参数用作成员,则会出错:

interface IPromise<T>{
    member:T    
}

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

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

因此

在实际的承诺定义中,我们有类似的东西:

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

由于我们使用T作为函数的参数 AB将由bivariance进行类型检查。因此,如果A是B的子集,或者B是A的子集,则它们是兼容的。

答案 1 :(得分:1)

我不确定为什么你没有收到错误,但我确实对如何得到警告提出了建议。根据angular.d.ts when定义如下:

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

因此,如果您想使用when进行更多输入,请使用:

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