Fin*_*ber 17 generics typescript
我想要实现的目标可以用代码最好地解释:
给定鞋子和服装类别:
class Shoe {
constructor(public size: number){}
}
Run Code Online (Sandbox Code Playgroud)
class Dress {
constructor(public style: string){}
}
Run Code Online (Sandbox Code Playgroud)
有一个只能容纳鞋子或连衣裙的通用盒子。不能同时包含两者:
class Box <T extends Shoe | Dress > {
}
Run Code Online (Sandbox Code Playgroud)
然后有一个实用程序类来处理移动鞋子:
class ShoeMover {
constructor(public size: number[]){}
}
Run Code Online (Sandbox Code Playgroud)
另外,还有一个用于移动连衣裙的实用程序类:
class DressPacker {
constructor(public style: string[]){}
}
Run Code Online (Sandbox Code Playgroud)
然后有一个通用的移动器,如果用Box<Shoe>or实例化,则Box<Dress>有一个mover使用 theShoeMover或 the 的方法DressPacker:
class Move<B extends Box<Shoe> | Box<Dress>> {
private box: B;
constructor(toMove: B) {
this.box = toMove;
}
public mover(tool: ShoeMover | DressPacker) {
}
}
Run Code Online (Sandbox Code Playgroud)
那么编译时保证应该是,如果Move用 实例化Box<Shoe>,那么该mover方法应该只接受ShoeMover。如果实例化为Box<Dress>. 该mover方法应该只接受DressPacker. 那是:
let shoemover = new Move(new Box<Shoe>());
// compile
shoemover.mover(new ShoeMover([21]))
// should not compile. But currently does
shoemover.mover(new DressPacker(["1"]))
Run Code Online (Sandbox Code Playgroud)
我尝试使用条件类型,但我想涉及泛型的事实使得预期的解决方案不起作用。基本上这是我尝试过的:
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;
Run Code Online (Sandbox Code Playgroud)
然后更改 from 的定义mover:
public mover(tool: ShoeMover | DressPacker) {
}
Run Code Online (Sandbox Code Playgroud)
到
public mover(tool: MoverFromEitherShoeOrDressB) {
}
or
public mover(tool: MoverFromEitherShoeOrDressA) {
}
Run Code Online (Sandbox Code Playgroud)
..但是这些并没有提供我所寻求的编译时间保证。
有人知道如何实现这一目标吗?
编辑。
接受的答案适用于上述场景。但有一个稍微不同的场景是行不通的。我决定更新,而不是创建另一个问题。这种情况是当 的构造函数Move更改为接受联合类型时。
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"]))
Run Code Online (Sandbox Code Playgroud)
leo*_*ory 15
你就快到了,你只需要在mover方法中也使用泛型,否则它不会知道T是什么。将泛型类型视为采用泛型 T 作为参数的方法,如下<>所示():
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>) {
}
}
Run Code Online (Sandbox Code Playgroud)
此外,我更改了Move定义以排除Box泛型,因为您可以轻松地将其封装在类内部定义中,但您的解决方案也可以使用:
type MoverFromEitherShoeOrDressA<T> =
T extends Box<infer U> ?
U extends Shoe ? ShoeMover :
U extends Dress ? DressPacker :
never:
never;
public mover(tool: MoverFromEitherShoeOrDressA<B>) { // <-- Here
}
Run Code Online (Sandbox Code Playgroud)
编辑:在此处添加游乐场:游乐场链接