#Not sure why function param is not being typed

15 messages · Page 1 of 1 (latest)

manic plinth
#

Hi all, I have this playground which has some of my code that I have a question about. I am working on a form validation library (never ending quest it seems) and I am using a generic with validator functions but I am not understanding why the argument is not getting typed the way I expect. I think something is off with my mental model.

Line 27, the value param is getting typed as any, but if I comment out line 20, value gets typed as string as I would expect. Is there any way to modify this to have value inferred as string by default?

rose ibexBOT
#
advdanny#0

Preview:```ts
type ValidatorResult =
| {success: true}
| {success: false; message: string}

type ValidatorOptions = {
state: {
focused: boolean
touched: boolean
dirty: boolean
}
}

type SyncValidator<V> = (value: V) => ValidatorResult
...```

manic plinth
#

Maybe just a limitation of how TS does things...

viscid wedge
#

The simplest reproduction:

rose ibexBOT
#
type Fn = ((a: string, b: number) => void) | ((a: string) => void)

const fn: Fn = (a) => {}
//              ^
// Parameter 'a' implicitly has an 'any' type.
viscid wedge
#

I'm guessing the reason is simply that you are allowed to ignore parameters, so (a) => {} fits both definitions and there's no way for TS to know which one you meant.

jaunty moon
#

Yeah, I think it's just a limitiation - TS is trying to figure out which union the function is supposed to match and it can't, so it doesn't know the type of a.

#

You could imagine a sort of higher-level logic that says "well, I don't know which union member I'm matching, but I only need the first param and in both cases the first param is a: string, so it must be a: string, but I just don't think TS operates at that kind of level.

viscid wedge
#

You could explicitly state which one you want by const validate: SyncValidator<string> = ....

jaunty moon
#

You might think Fn is equivalent to:

type Fn2 = (a: string, b?: number) => void

and in the case of declaring a single arg function like this, it works, but they're not really equivalent.

#

In general, the union form of Fn says that it could be a function that requires a second argument.

#

So it's not really safe, in general for TS to try to 'reduce' the Fn type into the Fn2 type (which is basically what it'd have to do to make this assignment work, I think)

manic plinth
#

This makes sense, especially that counterexample of why a narrowing of Fn into Fn2 would be unsafe. Thanks @jaunty moon and @viscid wedge. Have to come up with a different API now

#

Thanks @jaunty moon

#

Thanks @viscid wedge