为什么TypeScript类型保护在使用交集类型时不能正确缩小类型?

时间:2016-04-25 12:09:38

标签: typescript

使用TypeScript v1.8.10类型保护的以下代码给我一个编译器错误,但我不明白它为什么会失败:

export interface MyInterface {
    someFunction: () => void;
}

// ExtendedModelType is both a backbone model AND a MyInterface
export type ExtendedModelType = Backbone.Model & MyInterface;

class MyExtendedModelType extends Backbone.Model implements MyInterface {

    public someFunction(): void {
        let model: ExtendedModelType = new MyExtendedModelType();
        if (model instanceof MyExtendedModelType) {
            this.functionRequiringConcreteClass(model);
        }
    }

    private functionRequiringConcreteClass(param: MyExtendedModelType) { }
}

编译器在第13行失败:

error TS2345: Argument of type 'Model & MyInterface' is not assignable 
to parameter of type 'MyExtendedModelType'.
    Type 'MyInterface' is not assignable to type 'MyExtendedModelType'.
    Property 'functionRequiringConcreteClass' is missing in type 'MyInterface'.

由于交集类型,检查实例应该将'model'变成'Backbone.Model AND MyInterface'。但是然后将'model'传递给函数会让编译器抱怨数据结构。

这是一些我知道的边缘案例吗?或者这是编译器错误?

1 个答案:

答案 0 :(得分:1)

来自https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.5

  
    

类似地,交集类型具有以下可分配关系:

         
        
  1. 如果I中的任何类型可分配给T,则交叉类型I可分配给类型T.

  2.     
  3. 如果T可分配给I中的每种类型,则类型T可分配给交叉点类型I.

  4.        

因此,根据1,model(I)无法分配给MyExtendedModelType(T),因为model(I)中的任何类型都不能分配给MyExtendedModelType(T)

以下内容有效,因为MyInterface现在可分配给MyExtendedModelType(T)(正在删除private

export interface MyInterface {
   someFunction: () => void;
   functionRequiringConcreteClass: (param: MyExtendedModelType) => void;
}

// ExtendedModelType is both a backbone model AND a MyInterface
export type ExtendedModelType = Backbone.Model & MyInterface;

class MyExtendedModelType extends Backbone.Model implements MyInterface {

  public someFunction(): void {
    let model: ExtendedModelType = new MyExtendedModelType();
    if (model instanceof MyExtendedModelType) {
        this.functionRequiringConcreteClass(model);
    }
  }

  functionRequiringConcreteClass(param: MyExtendedModelType) { }
}