То, чего я хочу достичь, лучше всего объяснить в коде:
Данный класс обуви и одежды:
class Shoe {
constructor(public size: number){}
}
class Dress {
constructor(public style: string){}
}
Иметь коробку generi c, которая может содержать только Обувь или платье. Не может содержать оба:
class Box <T extends Shoe | Dress > {
}
Тогда есть вспомогательный класс, который заботится о движущейся обуви:
class ShoeMover {
constructor(public size: number[]){}
}
Также, вспомогательный класс для перемещения платьев:
class DressPacker {
constructor(public style: string[]){}
}
Затем используйте универсальный движок c, который при создании экземпляра с помощью Box<Shoe>
или Box<Dress>
имеет метод mover
, который использует либо ShoeMover
, либо DressPacker
:
class Move<B extends Box<Shoe> | Box<Dress>> {
private box: B;
constructor(toMove: B) {
this.box = toMove;
}
public mover(tool: ShoeMover | DressPacker) {
}
}
Тогда гарантия времени компиляции должна заключаться в том, что, если 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"]))
Я пытался использовать условные типы, но я предполагаю, что тот факт, что используются дженерики, заставляет задуманное решение не работать. В основном это то, что я пробовал:
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
с:
public mover(tool: ShoeMover | DressPacker) {
}
на
public mover(tool: MoverFromEitherShoeOrDressB) {
}
or
public mover(tool: MoverFromEitherShoeOrDressA) {
}
.. но эти не дал гарантий времени компиляции, которые я искал.
Кто-нибудь знает, как этого добиться?
Редактировать.
Принятый ответ работает для сценарий выше. Но есть немного другой сценарий, который не работает. Вместо того, чтобы создавать другой вопрос, я решил обновить. Сценарий заключается в том, что конструктор 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"]))
Playground Link