R
roblox-ts•2mo ago
Phantom

How to make discriminated union exhaustive while using t

const GAME_MODES = ["STANDARD", "TOURNAMENT", "CRAZY"] as const;
export type GameMode = (typeof GAME_MODES)[number];

export const gameModeToNameMap: Record<GameMode, string> = {
STANDARD: "Standard",
TOURNAMENT: "Tournament",
CRAZY: "Crazy",
};

const isBaseGameOptions = t.interface({
gridSize: t.interface({
rows: dimensionCheck,
columns: dimensionCheck,
}),
time: t.union(...timeControlOptions),
});

const isStandardGameOptions = t.intersection(
isBaseGameOptions,
t.interface({
gameMode: t.literal("STANDARD"),
}),
);

const isTournamentGameOptions = t.intersection(
isBaseGameOptions,
t.interface({
gameMode: t.literal("TOURNAMENT"),
winThreshold: t.numberConstrained(3, 10),
}),
);

// export const isGameOptions = t.interface({
// gameMode: t.valueOf(GAME_MODES),
// gridSize: t.interface({
// rows: dimensionCheck,
// columns: dimensionCheck,
// }),
// time: t.union(...timeControlOptions),
// });

export const isGameOptions = t.union(isStandardGameOptions, isTournamentGameOptions);
export type GameOptions = t.static<typeof isGameOptions>;
const GAME_MODES = ["STANDARD", "TOURNAMENT", "CRAZY"] as const;
export type GameMode = (typeof GAME_MODES)[number];

export const gameModeToNameMap: Record<GameMode, string> = {
STANDARD: "Standard",
TOURNAMENT: "Tournament",
CRAZY: "Crazy",
};

const isBaseGameOptions = t.interface({
gridSize: t.interface({
rows: dimensionCheck,
columns: dimensionCheck,
}),
time: t.union(...timeControlOptions),
});

const isStandardGameOptions = t.intersection(
isBaseGameOptions,
t.interface({
gameMode: t.literal("STANDARD"),
}),
);

const isTournamentGameOptions = t.intersection(
isBaseGameOptions,
t.interface({
gameMode: t.literal("TOURNAMENT"),
winThreshold: t.numberConstrained(3, 10),
}),
);

// export const isGameOptions = t.interface({
// gameMode: t.valueOf(GAME_MODES),
// gridSize: t.interface({
// rows: dimensionCheck,
// columns: dimensionCheck,
// }),
// time: t.union(...timeControlOptions),
// });

export const isGameOptions = t.union(isStandardGameOptions, isTournamentGameOptions);
export type GameOptions = t.static<typeof isGameOptions>;
I wanted to start adding custom rules depending on the game mode selected (right now only standard and tournament mode are available) but for demonstration purposes I added a "crazy" mode to show my problem. How can I enforce that my isGameOptions contains all game modes in the GAME_MODES array? This code would work without errors
Solution:
Apparently flamework/core is enough
Jump to solution
10 Replies
Tester
Tester•2mo ago
do you use flamework?
Phantom
PhantomOP•2mo ago
no
Tester
Tester•2mo ago
can you make an empty project with flamework template, generate the t from type and take it from compiled code? ^ i think it's gonna be way easier cause you can define the structure in the type and the flamework will do the figuring out for t structure
interface IData{
Gems: number;
Name: string;
ClassesList: keyof Instances;
}
const guard = Flamework.createGuard<IData>(); //and can you check the transpiled code for that part?
interface IData{
Gems: number;
Name: string;
ClassesList: keyof Instances;
}
const guard = Flamework.createGuard<IData>(); //and can you check the transpiled code for that part?
Phantom
PhantomOP•2mo ago
i cant exactly migrate to flamework but i think i can make a guard
type ContainsGameModes<T extends { gameMode: GameMode }> = GameMode extends T["gameMode"] ? T : never;
type ContainsGameModes<T extends { gameMode: GameMode }> = GameMode extends T["gameMode"] ? T : never;
this seems to work. would you have any better ideas? preferably it would throw a typeError instead of just defaulting to never but i am unfortunately not a type wizard
Tester
Tester•2mo ago
can you ask ai to make a type? i usually do that if the type is complex 🙄
Unknown User
Unknown User•2mo ago
Message Not Public
Sign In & Join Server To View
Phantom
PhantomOP•2mo ago
is there a smaller package i could use for that? is it @flamework/networking
Tester
Tester•2mo ago
Wdym? So you want it for networking? I think flamework is 3 packages @flamework/core (has to be all the time) @flamework/networking @flamework/components Or it might be 4 cause flamework has a transformer I think, or it's embedded in core
Phantom
PhantomOP•2mo ago
i want the type guards
Solution
Tester
Tester•2mo ago
Apparently flamework/core is enough

Did you find this page helpful?