嵌套的 Typescript 泛型
Nested Typescript Generics
我有以下 classes:
class Walls { }
class Furniture { }
class Layout<T extends Walls | Furniture> { }
class Space extends Layout<Walls> { }
class Room extends Layout<Furniture> { }
我需要创建这两个 classes:
class SpaceController extends LayoutController<Space> { }
class RoomController extends LayoutController<Room> {}
为此,我无法像这样创建 LayoutController
class:
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;
}
虽然多输入一个两种类型的参数解决方案也不错,如果 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
我有以下 classes:
class Walls { }
class Furniture { }
class Layout<T extends Walls | Furniture> { }
class Space extends Layout<Walls> { }
class Room extends Layout<Furniture> { }
我需要创建这两个 classes:
class SpaceController extends LayoutController<Space> { }
class RoomController extends LayoutController<Room> {}
为此,我无法像这样创建 LayoutController
class:
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;
}
虽然多输入一个两种类型的参数解决方案也不错,如果 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