Say I have a function that takes 2 args, and depending on the value of the first arg, the second arg may or may not be required.
For Example:
function calculate(item: 'icon' | 'category', state: IState): void {
if (arg1 === 'icon') {
// code in which I don't need to access anything in state
}
if (arg1 === 'category') {
// code in which I do need to access state
}
}
If I were to run this as is, I would get an error if I write
calculate('icon') // will cause an error
This will also throw an error because I am not passing a valid value for the second arg
calculate('icon', null) // will also cause an error
In order to not get any errors, I have to call it like this
calculate('icon', this.state) // acceptable as long as 'this.state' meets the IState definition
I want to be able to call the function without passing the second argument if the first argument = 'icon'. Like this
calculate('icon') // should not cause an error
However, if I call calculate like this it should cause an error
calculate('category') // should cause an error
Any help would be greatly appreciated!
You can use multiple overloads:
function calculate(item: 'icon'): void
function calculate(item: 'category', state: IState): void
function calculate(item: 'icon' | 'category', state?: IState): void {
if (item === 'icon') {
// code in which I don't need to access anything in state
}
if (item === 'category' && state) {
// code in which I do need to access state
}
}
calculate("icon")
calculate("category") //error
This is the solution I ended up going with. If anyone knows of a better way please share!
type ConditionalOptions<T, K extends keyof T> = T[K] extends null ? [] : [T[K]];
interface IPossibleValues {
icon: {
state: IState;
};
theme: null;
category: {
state: IState;
cardItem: any;
};
}
calculate = <T extends keyof IPossibleValues>(
type: T,
...options: ConditionalOptions<IPossibleValues, T>
): string => {
// code here
}
if this method is used, the value of each key in the interface IPossibleValues is what needs to be passed in to calculate as the second arg. Examples:
calculate('icon') // this will cause an error since no 'state' is passed in
calculate('icon', { state: stateVal }) // this will not generate a type error
calculate('theme') // this will not cause any type errors
calculate('theme', someValue) // this will cause an error
calculate('category', {
state: stateVal,
cardItem: cardVal,
}) // this will not cause an error
calculate('category', { state: stateVal }) // this will cause an error because 'cardItem' was not passed in
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With