I have a component that has 3 props: toValue
, fromValue
, children
. The first 2 of them are optional, but if one of them is specified, then the other must also be specified. The children
prop is a function that has the inputProps
argument, which should be equal to either the return type of toValue
function (TInputValue
), if specified, or TStateValue
.
I wrote the following code, but I didn't understand why inputProps
is any
in cases where the toValue
function is specified. How to fix it?
interface IP<T> {
value: T
onChange: (value: T) => void
}
interface A<TStateValue> {
toValue?: never
fromValue?: never
children: (inputProps: IP<TStateValue>) => null
}
interface B<TStateValue, TInputValue> {
toValue: (value: TStateValue) => TInputValue
fromValue: (value: TInputValue) => TStateValue
children: (inputProps: IP<TInputValue>) => null
}
type C<TStateValue, TInputValue> =
| A<TStateValue>
| B<TStateValue, TInputValue>
const propsWithoutToValue: C<number, string> = {
children: (inputProps) => null, // `inputProps` is `IP<number>`. Nice!
}
const propsWithToValue: C<number, string> = {
toValue: (value) => value.toString(), // The return type is a `string`, so the `inputProps` must be `IP<string>`
fromValue: (value) => Number(value),
children: (inputProps) => null, // `inputProps` is any, but must be `IP<string>`. How to fix it?
}
I have created a repo with my problem that I'm trying to solve:
point B: the reason typescript think you try to union 2 functions is because union function with the same object properties behave in the same way as union of both functions
this basically mean {b:((a:1)=>void)} | {b:((a:number)=>void)}
is literally {b:((a:1)=>void) | ((a:number)=>void)}
there are few things that I cant explain:
- the justification behind behavior shown in point A and B (what is the purpose)
- it seem like discriminated union (or union in general) not working properly with function type
- point A does not apply to propsWithoutToValue but apply to propsWithToValue, most likely is the after wave of point 2