How to make a conditional argument type?

Viewed 277

A function expect 2 arguments, a string and a callback. Depending on the first argument the type of the second may change.

function (eventName: string, fn: (dto?: any) => unknown) {}

In the above example if eventName is signup I want dto to be some object (interface).

2 Answers

You can overload functions:

 function named(eventName: "signup", fn: (dto: { /*...*/ }) => unknown);
 function named(eventName: string, fn: (dto?: any) => unknown) {
    // but only one may have a body
 }

You cannot define conditional types, because typescript has a rather static compiler and type checker.

To resolve the type checker issue you can use type union

FirstType && SecondType

or

FirstType || SecondType

Also you can use values in object with predefined types:

function (eventName: string, value: {first?: FirstType, second?: SecondType}) {}

So after you check the first argument you can you first or second value.

The best way is to split this logic in different functions, and to call them from the third one, that would be kind of router.

function handleSignup(value: SignupEvent) {}

function handleNonsignup(value: NonSignupEvent) {}

function (eventName: string, value: any) {
    //You do not know the actual type of this argument here, so any is rather fine(but not perfect choice)
    if (eventName === 'signup') {
        handleSignup(value)
    } else {
        handleNonsignup(value)
    }
}
Related