问题描述
我想要实现的目标可以用代码来最好地解释:
What I want to achieve can be best explained in code:
给出鞋类和服饰类:
class Shoe {
constructor(public size: number){}
}
class Dress {
constructor(public style: string){}
}
有一个仅包含Shoe或Dress的通用框.不能同时包含两者:
Have a generic box that can only contain Shoe or Dress. Can't contain both:
class Box <T extends Shoe | Dress > {
}
然后有一个实用类,可以处理运动鞋:
Then have a utility class that takes care of moving shoes:
class ShoeMover {
constructor(public size: number[]){}
}
还有一个用于移动连衣裙的实用程序类:
Also, a utility class for moving Dresses:
class DressPacker {
constructor(public style: string[]){}
}
然后有一个通用移动器,如果用Box<Shoe>
或Box<Dress>
实例化,则具有使用ShoeMover
或DressPacker
的mover
方法:
Then have a generic mover, that if instantiated with Box<Shoe>
or Box<Dress>
has a mover
method that makes use of either the ShoeMover
or the DressPacker
:
class Move<B extends Box<Shoe> | Box<Dress>> {
private box: B;
constructor(toMove: B) {
this.box = toMove;
}
public mover(tool: ShoeMover | DressPacker) {
}
}
然后,编译时间保证应该是,如果用Box<Shoe>
实例化Move
,则mover
方法应仅接受ShoeMover
.如果用Box<Dress>
实例化. mover
方法应仅接受DressPacker
.那就是:
Then the compile time guarantee should be that, if Move
is instantiated with Box<Shoe>
, then the mover
method should only accept ShoeMover
. If instantiated with Box<Dress>
. the mover
method should only accept DressPacker
. That is:
let shoemover = new Move(new Box<Shoe>());
// compile
shoemover.mover(new ShoeMover([21]))
// should not compile. But currently does
shoemover.mover(new DressPacker(["1"]))
我尝试使用条件类型,但是我猜想涉及泛型的事实使预期的解决方案无法正常工作.基本上这是我尝试过的:
I tried using conditional types, but I guess the fact that generics is involved makes the intended solution not to work. Basically this is what I have tried:
type MoverFromEitherShoeOrDressA<T> =
T extends Box<infer U> ?
U extends Shoe ? ShoeMover :
U extends Dress ? DressPacker :
never:
never;
and
type MoverFromEitherShoeOrDressB<T> =
T extends Box<Shoe> ? ShoeMover:
T extends Box<Dress> ? DressPacker:
never;
然后从以下位置更改mover
的定义:
Then changing the definition of mover
from:
public mover(tool: ShoeMover | DressPacker) {
}
到
public mover(tool: MoverFromEitherShoeOrDressB) {
}
or
public mover(tool: MoverFromEitherShoeOrDressA) {
}
..但是这些没有提供我所寻求的编译时间保证.
..but these did not give the compile time guarantees that I sought.
有人知道如何实现这一目标吗?
Anyone knows how to achieve this?
编辑.
可接受的答案适用于上述情况.但是有一个略有不同的方案是行不通的.我没有提出其他问题,而是决定进行更新.情况是Move
的构造函数更改为采用联合类型.
The accepted answer works for the scenario above. But there is a slightly different scenario which does not work. Instead of creating another question, I decided to update. The scenario is when the constructor of the Move
is changed to take in union type.
type Mover<T> =
T extends Shoe ? ShoeMover :
T extends Dress ? DressPacker :
never;
class Move<T extends Shoe | Dress> {
private box: Box<T>;
constructor(public toMove: Box<Shoe>[] | Box<Dress>[]) {
this.box = toMove;
}
public mover(tool: Mover<T>) {
}
}
let shoemover = new Move(new Array<Box<Shoe>>());
// compile
shoemover.mover(new ShoeMover([21]))
// should not compile. But currently does
shoemover.mover(new DressPacker(["1"]))
推荐答案
您快到了,您也只需要在mover
方法中使用泛型,否则它将不知道T
是什么.将通用类型视为将通用T用作参数,将<>
用作()
的方法:
You were almost there, you just need to use generics in the mover
method too, elseway it will not know what T
is is. See the generic type as a method which takes a generic T as a parameter, and <>
as ()
:
type Mover<T> =
T extends Shoe ? ShoeMover :
T extends Dress ? DressPacker :
never;
class Move<T extends Shoe | Dress> {
private box: Box<T>;
constructor(toMove: Box<T>) {
this.box = toMove;
}
public mover(tool: Mover<T>) {
}
}
此外,我更改了Move
定义以排除Box
泛型,因为您可以轻松地将其封装在类内部定义中,但是您的解决方案也可以使用:
Furthermore, I changed the Move
definition to exclude the Box
generic since you can easily encapsulate it in the class inner definitions, but your solution would work too with:
type MoverFromEitherShoeOrDressA<T> =
T extends Box<infer U> ?
U extends Shoe ? ShoeMover :
U extends Dress ? DressPacker :
never:
never;
public mover(tool: MoverFromEitherShoeOrDressA<B>) { // <-- Here
}
加入操场这里:
这篇关于TypeScript中具有泛型的条件类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!