I am working on a function where the return type needs to change based on one of its parameters. The parameter is called Command
and has two predefined values: 'trueOrFalse' or 'logSomething'. The ultimate goal is to make this function adaptable so that more commands can be added in the future.
type Command = 'trueOrFalse' | 'logSomething';
The function in question is
handleCommand(command: Command) => ???
. I want this function to automatically determine the return type based on the command provided. For instance, when you call handleCommand('trueOrFalse')
, it should know that the return type will be boolean
.
Below is what I currently have:
type Command = 'trueOrFalse' | 'logSomething'
type CommandHandler = {
'trueOrFalse': () => boolean;
'logSomething': () => void;
}
type Handlers = {
[Key in Command]: () => ReturnType<CommandHandler[K]>;
}
handleCommand<T extends Command>(command: T): ReturnType<CommandHandler[T]> {
const handlers: Handlers = {
'trueOrFalse': () => true,
'logSomething': () => { console.log('Test') }
}
const handler = handlers[command] as () => ReturnType<CommandHandler[T]>;
if (!handler) {
//error
}
return handler();
}
Even though my function seems error-free now after making several adjustments for typing issues like defining the Handlers
type and casting the handler
constant, the actual problem remains unresolved. When calling the function with either 'trueOrFalse'
or 'logSomething'
, the return type still ends up being boolean | void
. How do I get it to recognize that when 'trueOrFalse'
is used, the return type should strictly be a boolean
?
Edit:
It seems the root of the issue lies in an intermediary function that invokes handleEvent
.
This is the intermediary function:
triggerCommand(command: Command) {
return this.commandDispatcher.handleCommand(command);
}
Here's where the type error occurs:
let bool: boolean;
bool = triggerCommand('trueOrFalse'); // compiling error - cannot assign boolean | void to boolean
To fix this, I had to explicitly define the return type of triggerCommand
:
triggerCommand<T extends Command>(command: Command): ReturnType<CommandHandler[T]>
I apologize for not providing this context earlier as I overlooked the significance of this seemingly trivial intermediary function. It makes sense now why the expected behavior was not achieved.