interface Car {
price: number;
pickUpCost: number;
costPerKm: number;
}
interface IdleState {
state: "idle";
totalCost: number;
}
interface UsingState {
state: "using";
car: Car;
totalCost: number;
}
interface InvalidState {
state: "invalid";
}
interface PickUpAction {
type: "pickUp";
car: Car;
}
interface DropOffAction {
type: "dropOff";
totalKm: number;
}
interface AccidentAction {
type: "accident";
percentage: number;
}
type State = IdleState | UsingState | InvalidState;
type Action = PickUpAction | DropOffAction | AccidentAction;
function nextState(
action: Action,
currentState: State = {
state: "idle",
totalCost: 0,
}
): State {
switch (currentState.state) {
case "idle": {
if (action.type === "pickUp") {
return {
state: "using",
car: action.car,
totalCost: currentState.totalCost + action.car.pickUpCost,
};
} else {
return {
state: "invalid",
};
}
}
case "using": {
if (action.type === "dropOff") {
return {
state: "idle",
totalCost:
currentState.totalCost +
action.totalKm * currentState.car.costPerKm,
};
} else if (action.type === "accident") {
return {
...currentState,
totalCost:
currentState.totalCost +
(action.percentage * currentState.car.price) / 100.0,
};
} else {
return {
state: "invalid",
};
}
}
default: {
return {
state: "invalid",
};
}
}
}
function readSpyName(): string {
throw new Error("Implement this")
}
function readAction(): Action {
throw new Error("Implement this")
}
function main() {
const cars = new Map<string, Car>()
// read cars to Cars
const states = new Map<string, State>()
// loop through all events
const spy = readSpyName()
states.set(spy, nextState(readAction(), states.get(spy)))
}