这实际上是对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>>>>'.
我真的不知道如何做到这一点: - (
答案 0 :(得分:5)
正如我在评论中提到的,这看起来像编译器错误(或至少是设计限制)。我能找到的最小再现看起来像这样:
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>
的子类型,{ {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
,无论该类型是什么。这意味着tail
中Vector<T>
的实施将按预期返回Option<Vector<T>>
,但会与tail
中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>>