For context, I have this code:
interface CommandOptions {
id: number;
baseCommandName?: string;
commandName: string;
runtime: "Server" | "Client";
commandArgs?: Array<Omit<CommandArg, "type"> & { type: CommandArgType["Type"] }>
}
interface CommandArgTypeMap {
Boolean: boolean;
SignedInt: number;
UnsignedInt: number;
Float: number;
String: string;
Player: Player;
}
type InferCommandArgs<T extends CommandOptions & { commandArgs: readonly unknown[] }> =
{
[K in T['commandArgs'][number]['name']]: T['commandArgs'][number]['required'] extends true ? CommandArgTypeMap[T['commandArgs'][number]['type']] : CommandArgTypeMap[T['commandArgs'][number]['type']] | undefined;
}
const helpCommandOpts = {
id: 0,
commandName: "help",
runtime: "Server",
commandArgs: [{
name: "test",
required: true,
type: "Boolean"
}, {
name: "test2",
required: false,
type: "Player"
}]
} as const satisfies CommandOptions
const args: InferCommandArgs<typeof helpCommandOpts> = ...; // doesn't matter what the value is but looking more at the type
// it currently is
args.test // type is boolean | Player
args.test2 // type is boolean | Player | undefined
// adding more commands just adds on to the unions
// IT SHOULD BE
args.test // type is boolean
args.test2 // type is Player | undefined
I am having issues where it's turning the end result type into a whole bunch of unions when I don't want it like that, I am confused considering the types are the actual values ("test" instead of string)