【问题标题】:Nested Typescript Generics嵌套打字稿泛型
【发布时间】:2018-08-11 15:31:52
【问题描述】:

我有以下课程:

class Walls { }
class Furniture { }
class Layout<T extends Walls | Furniture> { }
class Space extends Layout<Walls> { }
class Room extends Layout<Furniture> { }

我需要创建这两个类:

class SpaceController extends LayoutController<Space> { }
class RoomController extends LayoutController<Room> {}

为此,我不能像这样创建LayoutController 类:

class LayoutController<T extends Layout>{ }

因为Layout 需要一个类型参数。

我可以改为创建这个:

class LayoutController<U, T extends Layout<U extends Walls | Furniture>>{ }

但这意味着我必须这样做:

class SpaceController extends LayoutController<Walls, Space> { }
class RoomController extends LayoutController<Furniture, Room> {}

我觉得这是多余的。此外,它为错误开辟了空间。没有什么能阻止我写作:

class RoomController extends LayoutController<Walls, Room> {}

我该如何解决这个问题?

更多关于LayoutController的详情:

class LayoutController<T> extends React.Component<{}, LayoutControllerState<T>>() { }
interface LayoutControllerState<T> { 
  selectedLayout: T;
}

【问题讨论】:

  • 您能否提供更多有关LayoutController 实施的详细信息?似乎可以将其定义为class LayoutController&lt;T extends Walls | Furniture&gt;,但也许我遗漏了一些东西。
  • @AlekseyL。它是一个 React 组件,在 state 中有一个名为 selected layout 的字段。 ``` 类 LayoutController 扩展 React.Component>() { } interface LayoutControllerState { selectedLayout: T; } ```
  • 好的,所以你可以输入内部布局文件为Layout&lt;T&gt;,其中TLayoutController的通用参数
  • @AlekseyL。 cmets 格式被破坏。请查看问题本身的编辑。
  • @AlekseyL.这意味着我必须写class SpaceController extends LayoutController&lt;Walls&gt; { },而不是LayoutController&lt;Space&gt;

标签: typescript generics nested-generics


【解决方案1】:

虽然多键入两个类型的参数解决方案也不错,如果 U 与布局预期的 T 不兼容,但如果正确指定了类型约束,则会给您适当的错误:

class Walls { height!: number; }
class Furniture { price!: number; }
class Layout<T extends Walls | Furniture> { children: T[] = []; }
class Space extends Layout<Walls> { private x: undefined; }
class Room extends Layout<Furniture> { private x: undefined; }

class LayoutController<U extends Walls | Furniture, T extends Layout<U>>{
    getValue(u: U) : void{}
}

class SpaceController extends LayoutController<Walls, Space> { }
class RoomController extends LayoutController<Furniture, Room> {}
class ErrController extends LayoutController<Walls, Room> {}  //Type 'Room' does not satisfy the constraint 'Layout<Walls>

我们可以使用条件类型从Layout 类型中提取泛型参数,并将其作为U 的默认值。因此我们不必指定冗余参数:

type ExtractLayoutParameter<T extends Layout<any>> = T extends Layout<infer U> ? U: never;
class LayoutController<T extends Layout<any>, U extends Walls | Furniture= ExtractLayoutParameter<T>>{
    getValue(u: U) : void{}
}

class SpaceController extends LayoutController<Space> { }
class RoomController extends LayoutController<Room> {}
new SpaceController().getValue(new Walls())
new SpaceController().getValue(new Furniture()) // error

我们也可以使用条件类型而不是 U,因此不允许用户将 U 更改为布局接受的派生类型(取决于您的用例,您决定的功能或设计限制) :

type ExtractLayoutParameter<T extends Layout<any>> = T extends Layout<infer U> ? U: never;
class LayoutController<T extends Layout<any>>{
    getValue(u: ExtractLayoutParameter<T>) : void{}
}

class SpaceController extends LayoutController<Space> { }
class RoomController extends LayoutController<Room> {}
new SpaceController().getValue(new Walls())
new SpaceController().getValue(new Furniture()) // error

【讨论】:

  • 感谢您的详细回复!不知道 Typescript 有这么多内容 :) 在使用条件类型、推断等之前,我会阅读更多内容。但是你的两个参数解决方案现在很简单。谢谢!
  • @AbdulsatarMohammed Typescript 中还有更多内容 ;-)。
猜你喜欢
  • 2021-12-20
  • 2021-09-10
  • 2021-12-06
  • 2020-12-17
  • 2019-07-30
  • 2015-11-27
  • 2016-10-19
  • 1970-01-01
  • 2021-11-26
相关资源
最近更新 更多