I have the following component:
// ...
type StringOrNumber = string | number;
type InputProps<T extends StringOrNumber> = {
value: T;
onSubmit: (value: T) => void;
};
export default function Input<T extends StringOrNumber>(props: InputProps<T>) {
const [value, setValue] = useState(props.value.toString());
// Called on enter & blur
const submitValue = () => {
// ts(2345): Argument of type 'string' is not assignable to parameter of type 'T'.
props.onSubmit(value);
};
// ...
return (
<input
{/* ... */}
onChange={(e) => setValue(e.target.value)}
value={value}
/>
);
}
The reason for the error above inside submitValue
is quite obvious as value
is always of type string
here, whilst onSubmit
expects a string
or a number
, depending on the generic T
of the component.
The problem is, that I don't know how to properly work around this error. I tried using type guards but that resulted in the same errors:
function isNumber(x: StringOrNumber): x is number {
return typeof x === 'number';
}
// ...
export default function Input<T extends StringOrNumber>(props: InputProps<T>): JSX.Element {
// ...
const submitValue = () => {
if (isNumber(props.value)) {
const numberValue = parseFloat(value) || 0;
// ts(2345): Argument of type 'number' is not assignable to parameter of type 'T'.
props.onSubmit(numberValue);
} else {
// ts(2345): Argument of type 'string' is not assignable to parameter of type 'T'.
props.onSubmit(value);
}
};
// ...
}
I guess the issue is that the type guard is only checking the type of props.value
here whilst it should somehow check what param type onSubmit
actually expects.
How is this done correctly?