代码之家  ›  专栏  ›  技术社区  ›  Emmanuel Touzery

类型A不能通过typescript 2.8条件类型分配给类型B

  •  7
  • Emmanuel Touzery  · 技术社区  · 6 年前

    这实际上是对 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 回复  |  直到 6 年前
        1
  •  5
  •   jcalz    6 年前

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

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

    这里一切都很好。所有类型参数都在 covariant 位置,这意味着如果 Y 是的子类型 X 然后 A<Y> 是的子类型 A<X> B<Y> 是的子类型 B<X> 。从那以后 B<T> 是的子类型 A<T> ,你可以推断,具体来说, B<B<T>> 是的子类型 B<A<T>> 。因此 bat 的属性 B 缩小范围 <<T>&燃气轮机; <<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 ,但不知何故,延迟条件类型导致了麻烦。从错误中可以清楚地看出,编译器正在跟踪 <T> 与兼容 <T> 通过检查 <<T>&燃气轮机; 与兼容 <<T>&燃气轮机; 通过检查 B<B<B<T>>> 与兼容 B<B<A<T>>> 通过哦哦。

    所以在类型检查器中有某种无限回归,它很早就退出了。。。这很好,否则编译器就会挂起。但当它摆脱困境时,它决定 <T> 与兼容 <T> ,这对我们来说是不好的(尽管像“成功纾困”这样的规则可能也是不好的)。


    所以,我的建议是做你做过的事 file the issue in GitHub 。我们看看他们怎么说。

    我不确定是否有任何真正简单的解决方法。如果找到答案,我将编辑此答案。

    祝你好运

        2
  •  3
  •   Titian Cernicova-Dragomir    6 年前

    问题是 Seq<T>.tail 退货 Option<Seq<T>> 虽然 Vector<T>.tail 退货 Option<Vector<T>> 。正如编译器详细地告诉我们的那样,这两种类型不兼容。最简单的解决方案是改变 Seq<T> 返回 Option 与当前类型相同的类型,无论该类型是什么。这意味着 tail 在里面 Vector<T> 将返回 选项(<);向量(<T>&燃气轮机; 如预期,但将符合 在里面 Seq 。我们可以使用 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>>