-
Notifications
You must be signed in to change notification settings - Fork 4
Description
I am still loving Variant and using it on a daily basis so MASSIVE thanks for this awesome lib :)
Up to now Variant has done just about everything I wanted. I have however started to run into a scenario that is causing problems. Its best described with an example.
e.g. I have the following
interface Attack {
kind: `attack`;
playerId: string;
}
interface Timeout {
kind: `timeout`;
playerId: string;
}
interface Surrender {
kind: `surrender`;
playerId: string;
}
export type BattleFinishedReason = Attack | Timeout | Surrender;
export const calculateIfBattleWasAbandoned = (reason: BattleFinishedReason ): boolean =>
matchKind(reason, {
timeout: () => true,
surrender: () => true,
attack: () => false,
});This is great, I release this code as v1. The server and client are working great.
I now do a v2 of the game and add a new type to the union..
...
interface Cancel {
kind: `cancel`;
playerId: string;
}
export type BattleFinishedReason = Attack | Timeout | Surrender | Cancel;The compiler will now yell at me that there is a missing option in the calculateIfBattleWasAbandoned match which is great, so I add that:
export const calculateIfBattleWasAbandoned = (reason: BattleFinishedReason ): boolean =>
matchKind(reason, {
timeout: () => true,
surrender: () => true,
attack: () => false,
cancel: () => true,
});I then push the code as a v2 release. The server is happy because it can handle the new case but the problem is there are clients still on v1 of the game and so their calculateIfBattleWasAbandoned matcher doesnt know how to handle the Cancel BattleFinishedReason ..
I know this can be solved with a default option in the matcher:
export const calculateIfBattleWasAbandoned = (reason: BattleFinishedReason ): boolean =>
matchKind(reason, {
timeout: () => true,
surrender: () => true,
attack: () => false,
cancel: () => true,
// Saving future me some headaches
default: () => false
});... but this breaks the exhustive checking which I rely on so much.
So is it possible for the matcher to be both exhaustive AND have a default?