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

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

接口定义如下:

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>

我不确定你为什么没有收到错误,但我确实有一个关于如何收到警告的建议。根据angular.d.tswhen是这样定义的:

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

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

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

这是根据规格。这是您的简化示例:

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

原因是函数参数的双方差兼容性。请参阅此 link 以获取文档 + 原因如下: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 在哪里使用类型参数作为成员,它会出错:

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 将通过双方差进行类型检查。因此,如果 A 是 B 的子集或 B 是 A 的子集,则它们是兼容的。