reactjstypescripttypestype-declarationtype-definition

Is there a way to solve a type declaration that accepts a union of a string and a function?


I've this type definition, incomplete at the moment:

export type Type1 = string;

export type Type2 = string | { [index: string]: any } | Array<string | undefined | boolean>;

export type Type3 = { [index: string]: any } | Array<string | undefined | boolean>;

export type Type4 = (arg1?: Type2 | Type3, arg2?: Type3) => string | undefined;

export default function myLibrary(arg1?: Type1, arg2?: Type2, arg3?: Type3): Type4;

Normally the library is used in scenarios like the one of the following example, types declaration works properly in this example, within React application:

const myCustomLibrary = myLibrary('string')
...
<span className={myCustomLibrary({
  key: value
})}/>

where value can be anything like a boolean, string, object..

But I said incomplete definition because it is not covering the following scenario, still within a React application:

<span className={myLibrary('string', {
  key: value
})}/>

Basically myLibrary can return a function or also a string, depending of the values received as input according to a specific internal logic. So the type Type4 could also be a string, not only a method returning a string. Current type declaration offers just the type Type4 as output, it misses a simple string. In fact while returning a string, here is the error:

TS2322: Type 'Type4' is not assignable to type 'string'.

So I thought to add a string to the return value of myLibrary

export default function myLibrary(arg1?: Type1, arg2?: Type2, arg3?: Type3): Type4 | string;

but this ruins other scenarios currently working (the one receiving the actual Type4 and it gives this error

Cannot invoke an expression whose type lacks a call signature. Type 'string | Type4' has no compatible call signatures.ts(2349)

Feel in a loophole, what am I doing wrong? I could solve everything defining Type4 as any, but that is not what I want to achieve.


Solution

  • The solution is indeed the usage of Overloads concept, thanks @AlekseyL. for the tip in the comments, for clearer reference I add here the proper code fix.

    export default function myLibrary(arg1?: Type1, arg2?: Type1): Type4;
    
    export default function myLibrary(arg1: Type1, arg2: Type3 | undefined): string;
    
    export default function myLibrary(arg1: Type1, arg2: Type2, arg3: Type3): string;