0

鉴于以下情况:

interface Component {}
interface Composite<component extends Component> {
  getChildren(): component[];
}
class StackSegment implements Component {}
class Stack implements Composite<StackSegment> {
    getChildren(): StackSegment[] {
        return new Array<StackSegment>();
    }
}

为什么以下会导致编译器错误?

class Bar<component extends Component = StackSegment, 
       composite extends Composite<component> = Stack> {
}

我得到的错误(在 Stack 上作为复合的默认值)表示 StackSegment 不可分配给类型“组件”。

4

3 回答 3

1

我认为问题在于第二个类型参数取决于第一个。我的意思是,如果第一个参数是类型,P那么第二个参数必须是类型Composite<P>(假设Pimplments Component)。

但是当您分配默认类型时,您可以这样做:

let b = new Bar<P>();

这里我没有传递第二个类型参数,所以 TypeScript 假定它是Stack. 但是,Stack不扩展P

类型参数的默认值并不总是强制执行类型约束,因此不能声明这样的类型。

于 2018-03-22T17:05:45.957 回答
1

注意:在接下来的内容中,我使用短大写标识符作为类型参数,作为常规约定。您可以随意替换CNwithcomponentCSwith composite(但我建议不要对泛型类型参数使用常规标识符)


我不确定您的用例是什么,但默认类型参数不设置约束。在您的代码中,

class Bar<CN extends Component = StackSegment, 
       CS extends Composite<CN> = Stack> {  // error
}

类型参数CN不需要是StackSegment因此有可能Stack不满足 的约束Composite<CN>。处理它的一种方法是制作复合材料,Composite<CN>而不是Stack

class Bar<CN extends Component = StackSegment, 
       CS extends Composite<CN> = Composite<CN>> {  // okay
}

如果你真的想看到默认值Stack(例如,如果Stack有一些额外的方法Composite<CN>没有),那么你可以这样做:

class Bar<CN extends Component = StackSegment, 
       CS extends Composite<CN> = Stack & Composite<CN>> {  // okay
}

因为Stack & Composite<StackSegment>与 的结构类型相同Stack。但同样,我不知道你的用例。到目前为止,您会得到以下内容:

interface OtherComponent extends Component {
    thingy: string;
}

class OtherComposite implements Composite<OtherComponent> {
    getChildren(): OtherComponent[] {
        throw new Error("Method not implemented.");
    }
}

new Bar(); // Bar<StackSegment, Stack> as desired
new Bar<OtherComponent, OtherComposite>(); // also makes sense

// but this is a Bar<OtherComponent, Stack & Composite<OtherComponent>>
new Bar<OtherComponent>(); // wha?
// which is weird.

您是否打算只使用一个默认参数?如果没有,也许有更好的方法来表示泛型。但是如果没有更多用例信息,我不知道如何为您提供建议。

祝你好运。


编辑:我认为你想要的一种丑陋的语法是在一个参数中指定两种类型,如下所示:

class Bar<CC extends [Component, Composite<CC[0]>]=[StackSegment, Stack],
    CN extends CC[0] = CC[0],
    CS extends CC[1] = CC[1]> {    
}

在上面,CC是一个带有您想要的约束的类型的双元组(第二个参数必须与Composite<>第一个参数兼容),并且它默认[StackSegment, Stack]为所需的对。(CNandCS类型只是为了方便而存在,因此您不需要将其CC[0]用于组件类型和CC[1]复合类型)。

现在的行为是这样的:

new Bar(); // CN is StackSegment and CS is Stack, as desired
new Bar<[OtherComponent, OtherComposite]>(); // also makes sense

但是你不能像以前那样轻易地打破它:

new Bar<[OtherComponent]>(); // error
new Bar<[OtherComponent, Stack]>(); // error

好的,再次祝你好运!

于 2018-03-22T18:17:36.363 回答
0

更改导致编译器错误的代码行如下:

class Bar<component extends Component = StackSegment, 
    composite extends Composite<Component> = Stack> {}  

消除了错误。

现在的问题是,它是否会在被覆盖时按预期工作。

于 2018-03-22T17:22:59.137 回答