类型A不能分配给带有typescript 2.8条件类型的类型B.

时间:2018-03-24 19:17:22

标签: typescript

这实际上是对typescript 2.8 Exclude: possible to supercharge the 'partition' type?的跟进 - 我在代码中引入条件类型时遇到了问题。

请注意,条件类型是typescript 2.8的新类型,因此目前必须使用typescript 2.8rc构建它。

我已将当前的问题减少到这个非常小的测试用例:

export class Option<T> {
    toVector(): Vector<T> {
        return <any>undefined;
    }
}

interface Seq<T> {
    tail(): Option<Seq<T>>;
}

class Vector<T> implements Seq<T> {

    tail(): Option<Vector<T>> {
        return <any>undefined;
    }

     // the next line breaks the compilation
    partition2<U extends T>(predicate:(v:T)=>v is U): [Vector<U>,Vector<Exclude<T,U>>];
    partition2(predicate:(x:T)=>boolean): [Vector<T>,Vector<T>];
    partition2<U extends T>(predicate:(v:T)=>boolean): [Vector<U>,Vector<any>] {
        return <any>undefined;
    }
}

新行是partition2的第一次重载。如果你评论它,所有构建都很好。

如果使用--strict进行编译,则会失败并出现令人困惑的构建错误:

t.ts(13,5): error TS2416: Property 'tail' in type 'Vector<T>' is not assignable to the same property in base type 'Seq<T>'.
  Type '() => Option<Vector<T>>' is not assignable to type '() => Option<Seq<T>>'.
    Type 'Option<Vector<T>>' is not assignable to type 'Option<Seq<T>>'.
      Types of property 'toVector' are incompatible.
        Type '() => Vector<Vector<T>>' is not assignable to type '() => Vector<Seq<T>>'.
          Type 'Vector<Vector<T>>' is not assignable to type 'Vector<Seq<T>>'.
            Types of property 'tail' are incompatible.
              Type '() => Option<Vector<Vector<T>>>' is not assignable to type '() => Option<Vector<Seq<T>>>'.
                Type 'Option<Vector<Vector<T>>>' is not assignable to type 'Option<Vector<Seq<T>>>'.
                  Types of property 'toVector' are incompatible.
                    Type '() => Vector<Vector<Vector<T>>>' is not assignable to type '() => Vector<Vector<Seq<T>>>'.
                      Type 'Vector<Vector<Vector<T>>>' is not assignable to type 'Vector<Vector<Seq<T>>>'.
                        Types of property 'tail' are incompatible.
                          Type '() => Option<Vector<Vector<Vector<T>>>>' is not assignable to type '() => Option<Vector<Vector<Seq<T>>>>'.
                            Type 'Option<Vector<Vector<Vector<T>>>>' is not assignable to type 'Option<Vector<Vector<Seq<T>>>>'.
                              Types of property 'toVector' are incompatible.
                                Type '() => Vector<Vector<Vector<Vector<T>>>>' is not assignable to type '() => Vector<Vector<Vector<Seq<T>>>>'.
                                  Type 'Vector<Vector<Vector<Vector<T>>>>' is not assignable to type 'Vector<Vector<Vector<Seq<T>>>>'.
                                    Types of property 'tail' are incompatible.
                                      Type '() => Option<Vector<Vector<Vector<Vector<T>>>>>' is not assignable to type '() => Option<Vector<Vector<Vector<Seq<T>>>>>'.
                                        Type 'Option<Vector<Vector<Vector<Vector<T>>>>>' is not assignable to type 'Option<Vector<Vector<Vector<Seq<T>>>>>'.
                                          Types of property 'toVector' are incompatible.
                                            Type '() => Vector<Vector<Vector<Vector<Vector<T>>>>>' is not assignable to type '() => Vector<Vector<Vector<Vector<Seq<T>>>>>'.
                                              Type 'Vector<Vector<Vector<Vector<Vector<T>>>>>' is not assignable to type 'Vector<Vector<Vector<Vector<Seq<T>>>>>'.
                                                Type 'Vector<Vector<Vector<Seq<T>>>>' is not assignable to type 'Vector<Vector<Vector<Vector<T>>>>'.

我真的不知道如何做到这一点: - (

2 个答案:

答案 0 :(得分:5)

正如我在评论中提到的,这看起来像编译器错误(或至少是设计限制)。我能找到的最小再现看起来像这样:

interface A<T> {
    bat: B<A<T>>;
}

interface B<T> extends A<T> {
    bat: B<B<T>>;
    boom: true
}

这里的一切都没问题。所有类型参数都在covariant个位置,这意味着如果YX的子类型,那么A<Y>A<X>的子类型,{ {1}}是B<Y>的子类型。由于B<X>B<T>的子类型,因此您可以推断出,A<T>B<B<T>>的子类型。因此,B<A<T>>的{​​{1}}属性可以将bat缩小为B

现在观察当我们向B<A<T>>添加条件类型(没有立即评估)时会发生什么:

B<B<T>>

它爆炸了。毫无疑问,B仍然属于interface A<T> { bat: B<A<T>>; } interface B<T> extends A<T> { // ^ error // Interface 'B<T>' incorrectly extends interface 'A<T>'. bat: B<B<T>>; boom: T extends any ? true : true } 类型,但不知何故,延迟条件类型会导致问题。从错误中可以看出,编译器正在通过检查boom是否与true兼容来追查B<T>是否与A<T>兼容。 {1}}与B<B<T>>兼容...呃哦。

因此,类型检查器中出现了某种无限回归,这种回归很早就会纾困......这样做很好,因为否则编译器会挂起。但是当它退出时,它决定B<A<T>> B<B<B<T>>>不兼容,这对我们来说是不利的(尽管像#34这样的规则拯救成功&#34 ;也许很糟糕。)

所以,我的建议是做你做的和file the issue in GitHub。我们会在那里看到他们的意见。

我不确定是否有任何非常简单的解决方法。如果我找到答案,我会编辑这个答案。

祝你好运!

答案 1 :(得分:3)

问题是Seq<T>.tail返回Option<Seq<T>>Vector<T>.tail返回Option<Vector<T>>。这两种类型不兼容,正如编译器详细告诉我们的那样。最简单的解决方案是更改Seq<T>以返回与当前类型相同类型的Option,无论该类型是什么。这意味着tailVector<T>的实施将按预期返回Option<Vector<T>>,但会与tailSeq的定义兼容。我们可以使用this类型执行此操作:

export class Option<T> {
    toVector(): Vector<T> {
        return <any>undefined;
    }
}

interface Seq<T> {
    tail(): Option<this>;
}

class Vector<T> implements Seq<T> {

    tail(): Option<this> {
        return <any>undefined;
    }

    // the next line breaks the compilation
    partition2<U extends T>(predicate:(v:T)=>v is U): [Vector<U>,Vector<Exclude<T,U>>];
    partition2(predicate:(x:T)=>boolean): [Vector<T>,Vector<T>];
    partition2<U extends T>(predicate:(v:T)=>boolean): [Vector<U>,Vector<any>] {
        return <any>undefined;
    }
}

declare var v: Vector<number>;
var d = v.tail().toVector() // will be Vector<Vector<number>>