Class
enum VehicleType {
car = 'CAR',
ship = 'SHIP',
}
interface BaseMoveDto {
type: VehicleType;
}
interface CarMoveDto extends BaseMoveDto {
type: VehicleType.car;
}
interface ShipMoveDto extends BaseMoveDto {
type: VehicleType.ship;
}
type VehicleMoveDto = CarMoveDto | ShipMoveDto;
abstract class Vehicle {
abstract move(dto: VehicleMoveDto): VehicleMoveDto;
}
class Car extends Vehicle {
move(dto: CarMoveDto) {
return dto;
}
}
class Ship extends Vehicle {
move(dto: ShipMoveDto) {
return dto;
}
}
Usage
class VehicleService {
getVehicle(type: VehicleType) {
switch (type) {
case VehicleType.car:
return new Car();
case VehicleType.ship:
return new Ship();
default:
throw new Error('invalid vehicle type');
}
}
calculateMovement(dto: VehicleMoveDto) {
const vehicle = this.getVehicle(dto.type);
return vehicle.move(dto);
}
}
Problem
Argument of type 'VehicleMoveDto' is not assignable to parameter of type 'never'.
The intersection 'ShipMoveDto & CarMoveDto' was reduced to 'never' because property 'type' has conflicting types in some constituents.
Type 'CarMoveDto' is not assignable to type 'never'.
According to the error, Typescript intersect move() arguments instead of union, making the dto argument become type never and cause the error. Anything I misunderstood about typescript? Are there any solution to do what I want?
Not a solution
I know I can do this without any problem.
class VehicleService {
calculateMovement(dto: VehicleMoveDto) {
switch (dto.type) {
case VehicleType.car:
return new Car().move(dto);
case VehicleType.ship:
return new Ship().move(dto);
default:
throw new Error('invalid vehicle type');
}
}
otherMethod(type: VehicleType) {
// other method use switch case as well
}
}
But with implementation as above, I can't reuse the switch case for other methods.
