Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Differentiating return type based on argument

Tags:

typescript

I'm trying to type a function that either accepts a string or string[] and returns either a bool or bool[] respectively. I've tried both using generics types and overload but both seem to throw some kind of error:

// generic way
function genericWay<T extends string | string[]>(val: T): T extends string ? boolean : boolean[] {
    if (typeof val === 'string'){
        return true // Type 'true' is not assignable to type 'T extends string ? boolean : boolean[]'
    }
    return [true] // Type 'true[]' is not assignable to type 'T extends string ? boolean : boolean[]'
}

const a1 = overloadWay('bbb')
const a2 = genericWay(['bbb'])
const a3 = genericWay(5333) // should throw error


// overload way
function overloadWay(val: string[]): boolean[]; // This overload signature is not compatible with its implementation signature.
function overloadWay(val: string): boolean {    
    if (typeof val === 'string'){
        return true
    }
    return [true] // Type 'boolean[]' is not assignable to type 'boolean'.
}

const b1 = overloadWay('bbb')
const b2 = overloadWay(['bbb'])
const b3 = overloadWay(5333) // should throw error

ts playground

  1. From the first example - it seems my return type is incorrect?
  2. For the overload way, for some reason it's not picking up on type check to differentiate between the two input types.
like image 994
cat-t Avatar asked Jun 14 '26 03:06

cat-t


2 Answers

Since another answer already provides with how to fix the warning in the generic way, which requires explicit type casting, here is how you can use function overloading to achive the same goals.

Your overload way definition is not correct. You need to specify all the overloads before the function and the implementing function should contain all the possible inputs and outputs in its signature. You may resort to any in the implementation, but I do not think that's advisable wherever you can avoid.

Here is the overload way

// overload way
function overloadWay(val: string[]): boolean[];
function overloadWay(val: string): boolean ;
function overloadWay(val: string| string[]): boolean | boolean[] {    
    if (typeof val === 'string'){
        return true
    }
    return [true]
}

// b1 is boolean
const b1 = overloadWay('bbb')

// b2 is boolean[]
const b2 = overloadWay(['bbb'])

// shows error
const b3 = overloadWay(5333) 

TS Playground

like image 190
Nishant Avatar answered Jun 18 '26 00:06

Nishant


I've applied some changes to the generic way, to have a separate Generic type, and asserted the returned value type with as, check Here

type genType<T> = T extends string ? boolean : boolean[];

function genericWay<T extends string | string[]>(val: T): genType<T> {
    if (typeof val === 'string'){
        return true as genType<T>
    }
    return [true] as genType<T>
}

const a1 = genericWay('bbb')
const a2 = genericWay(['bbb'])
const a3 = genericWay(5333) // should throw error
like image 40
Zac Avatar answered Jun 18 '26 00:06

Zac