带泛型的Typescript类声明语法

时间:2018-03-22 16:51:02

标签: typescript generics parameterization

鉴于以下内容:

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不能分配给&#39;组件&#39;。

3 个答案:

答案 0 :(得分:1)

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

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

let b = new Bar<P>();

这里我没有传递第二个类型参数,因此TypeScript假设它是Stack。但是,Stack不会延伸P

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

答案 1 :(得分:1)

注意:在下面我将使用类型参数的短大写标识符作为常规约定。您可以随意将CN替换为component,将CS替换为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<>兼容),并且它默认为对{根据需要{1}}。 ([StackSegment, Stack]CN类型就是为了方便起见,因此您不需要对组件类型使用CS,对于复合类型使用CC[0]

现在行为是这样的:

CC[1]

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

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

好的,祝你好运!

答案 2 :(得分:0)

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

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

消除了错误。

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