#Return value is not assignable to return type of function

26 messages · Page 1 of 1 (latest)

empty quartz
#

I have a simple function like this

type TUndefinedIfEmpty<T> = T extends '' ? undefined : T;

/** 
 * If value is an empty string, Return undefined. 
 * Return value unchanged in all other cases.
 */
const undefinedIfEmpty = <T,>(value: T): TUndefinedIfEmpty<T> => {
  if(typeof value === 'string' && value === '') {
    return undefined;
  }
  return value;
}

In this case, typescript complains that

Type 'undefined' is not assignable to type 'TUndefinedIfEmpty<T>'

Why does this error out when the return type is specified?
I could just remove the return type and just work with the string | undefined types but I'm curious why that errors?

regal saddleBOT
#
krimson#7581

Preview:```ts
type TUndefinedIfEmpty<T> = T extends ""
? undefined
: T

const undefinedIfEmpty = <T>(
value: T
): TUndefinedIfEmpty<T> => {
// why does this error out?
if (typeof value === "string" && value === "")
return undefined
return value
}

const test1 = undefinedIfEmpty(1)
...```

arctic lance
#

conditional return types don't work how you think they do

#

use overloads

#

actually might not be overloads. just give a more general return

#

you could make it more specific with overloads but i would think a normal return would be sufficient here?

empty quartz
#

hmm why wouldn't it work? Is it some logical issue in what I'm trying to do or is is that the type checker is not smart enough to work with conditional return types?

arctic lance
#

although "" wouldn't be in the return type hold on

#

conditional return types just kinda don't work. i haven't really thought enough about it to say if it's a limitation or a design choice

empty quartz
#

hmm makes sense

arctic lance
empty quartz
#

I'll try and give overloading a shot. I think that might work 🤔

arctic lance
#

im really tired right now so i might not be giving the best perspective sorry

empty quartz
#

My goal was to get a more specific type from the return as opposed to just a string | undefined

#

no problem!

burnt rose
#

Generic parameter cannot be narrowed in implementation, so your function return (which depends on T) doesn't get specialized.

empty quartz
#

ok so I'm assuming theres no way around this due to the type checker limitation. The only way would be to force cast the return I guess.

#

I tried function overloading but tbh I'm really a newbie and dont think I'm doing it correctly

regal saddleBOT
#
krimson#7581

Preview:```ts
type TUndefinedIfEmpty<T> = T extends ""
? undefined
: T

function undefinedIfEmpty<T extends "">(
value: T
): undefined
function undefinedIfEmpty<T extends any>(
value: T
): T | undefined {
if (typeof value === "string" && value === "")
return undefi
...```

empty quartz
#

basically the way forward would be to just do a

return ... as unknown as TUndefinedIfEmpty<T>
burnt rose
#

If you are doing overloads, you would just get rid of the entire generic conditional.

regal saddleBOT
#
Burrito#6903

Preview:```ts
function undefinedIfEmpty(value: ""): undefined
function undefinedIfEmpty<T>(value: T): T
function undefinedIfEmpty(value: unknown): unknown {
if (typeof value === "string" && value === "")
return undefined
return value
}

const test1 = undefinedIfEmpty(1)
...```

burnt rose
#

Do note that overloads aren't type safe either, function body only gets type checked against implementation signature, not the overload signatures.

#

But your example isn't really common either, normally this type of checks are only used because you have no idea what the value could be.

empty quartz
#

yeah I realize its probably not common. For my use case, the values are provided by users and I want to "clean" them. So you're right, in this case I have no idea what the values provided are.

#

Either way, this has been incredibly helpful, thank you for your time!