Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Union type of two functions in Typescript

I have a situation where I have a type which is a union of two functions which have a literal value as the type of one of their arguments. Boiled down to a minimal example, it is essentially this:

type FetchMini = (id: number, representation: 'mini') => MiniUser;
type FetchFull = (id: number, representation: 'full') => FullUser;

function f(fetchUser: FetchMini | FetchFull) {
  fetchUser(2, 'mini');
  fetchUser(2, 'full');
}

Both of these calls fail the compiler with the message:

Cannot invoke an expression whose type lacks a call signature. Type 'FetchMini | FetchFull' has no compatible call signatures.`

I think I understand the reason why this happens, (...I think) but what could I do about it?

Here's a similar question, however it got no answers: Union of functions is not callable even with parameters that meet each function's constraints

like image 241
nickf Avatar asked Apr 27 '17 16:04

nickf


1 Answers

Your fetchUser() is essentially an overloaded function which accepts both mini and full, thus should be intersection-typed, rather than union.

type MiniUser = { name: string }
type FullUser = { firstName: string, lastName: string, age: number }

type FetchMini = (id: number, representation: 'mini') => MiniUser;
type FetchFull = (id: number, representation: 'full') => FullUser;
type FetchBoth = FetchMini&FetchFull

function f(fetchUser: FetchBoth) {
    fetchUser(2, 'mini');
    fetchUser(2, 'full');
}

function fetchBoth(id: number, representation: 'mini'): MiniUser
function fetchBoth(id: number, representation: 'full'): FullUser
function fetchBoth(id: number, representation: 'mini' | 'full') {
    if (representation==='mini')
        return { name: 'Mini' }
    if (representation==='full')
        return { firstName: 'Full', lastName: 'User', age: 20 }
}
f(fetchBoth)

PlayGround

As a rule of thumb, when you declare a function that accepts args of both type A and B, the function should be &-typed.

like image 125
ntabee Avatar answered Sep 20 '22 12:09

ntabee