Reputation: 5061
As I understand, TS prefers direct type usages over "boxed" ones (e.g. in function) to infer a generic type from.
type Props<O, V> = {
options: O[]
getOptionValue: (o: O) => V
value?: V
onChange?: (v: V, o: O) => void
}
In this snippet type V
is inferred from value
field which is undesirable since value
property is optional. Can I somehow force generic type inference to rely on getOptionValue
property?
Sandbox example where if no value
passed to a component its onChange
argument v
becomes unknown
Upvotes: 1
Views: 65
Reputation: 328142
I'm somewhat inclined to close this as a duplicate of this question. The compiler doesn't make multiple inference passes when trying to infer the types of a single object.
My workaround suggestion here would be the same as there: split your function into multiple parameters instead of a single parameter with multiple properties. You could even make a helper function like this:
const props = <O, V>(
options: O[],
getOptionValue: (o: O) => V,
value?: V,
onChange?: (v: V, o: O) => void
): Props<O, V> => ({ options, getOptionValue, onChange })
And then use it:
const theProps = props(
[""],
(o) => "test",
undefined,
(v, o) => v.length < o.length
);
Here you can see that O
and V
are properly inferred to be string
and v
is not unknown
in the onChange
callback. You can use also this with JSX via spread:
const c = <C {...theProps} />;
It's not perfect, since you're getting inference in exchange for a multi-step jsx element creation. But it does work.
Upvotes: 2
Reputation: 3476
I don't think it's possible, because even if you remove the value
property entirely typescript still won't use getOptionValue
to infer the type.
function C<O, V>(props: {
options: O[]
getOptionValue: (o: O) => V
onChange?: (v: V, o: O) => void
}) {}
C({
options: [""],
getOptionValue: (o) => "test",
onChange: (v, o) => v.test // error: v is STILL 'unknown'
})
Upvotes: 1