I am trying to assing an onChange and onKeyDown to an Input component with TypeScript and this is getting out of hand.
I have this Input component:
import React, { ChangeEvent, KeyboardEvent } from 'react'
import { InputStyle } from './Input-style'
type InputProps = {
name: string
value: string | number
type?: string
placeholder?: string
onBlur?: () => void
onKeyDown?: (e: KeyboardEvent) => void
onChange?: (e: ChangeEvent<HTMLInputElement>) => void
}
export const Input = (props: InputProps) => (
<InputStyle
type={props.type ? props.type : 'text'}
name={props.name}
id={props.name}
placeholder={props.placeholder}
value={props.value}
onKeyDown={props.onKeyDown}
onChange={props.onChange}
onBlur={props.onBlur}
/>
)
Then I am using the component to do two things, validate that the keypress entered is a number and then add the value, and what seems to be an easy task is just giving me all sorts of TypeScript errors about the type
import React, { KeyboardEvent, ChangeEvent } from 'react'
export const renderInput = () => {
const [rate, setRate] = useState<number>(0)
// I want to add the value only if is a number and between 0-1 no letters
const addRate = (e: KeyboardEvent | ChangeEvent) => {
const element = e.target as HTMLInputElement
const value = element.value
if ('key' in e) {
const reg = /[0-9]/
// If is not a letter
if (reg.test(e.key)) {
// Add the value but here now it breaks
setRate(isNaN(value) || value > 1 ? 0 : value)
}
}
}
return (
<Input
type='number'
name='Conversion Rate'
value={rate === 0 ? '' : rate}
placeholder='Percentage Decimal number'
onKeyDown={addRate}
onChange={addRate}
/>
)
}
But at this point TypeScript errors with
Argument of type 'string | 0' is not assignable to parameter of type 'SetStateAction'
I am really confused cause before trying to check for the keyDown it worked.
CodePudding user response:
I am guessing element.value is of type string.
You can parse it to number with parseInt(element.value) or element.value
That would be : const value = element.value
CodePudding user response:
onKeyDown dispatches value as character. Therefore Typescript conflict types.
You can convert in parseInt(value, 10).
You should note that field type number already accept only numbers and "e" of exponential.
CodePudding user response:
None of the answers worked for me, they might sound right in principal, but it just conflicted one against each other as per my example. I was heading to TypeScript hell, so I got out of it by using a regular text input and some regex:
const addRate = (val: string) => {
// If it's a number and is higher than 1 exit
if (!isNaN(parseInt(val)) && parseFloat(val) > 1) {
return
}
// Regex to allow only decimal mumbers
const reg = /^\d*(?:[.]\d*)?$/
if (reg.test(val)) setRate(val)
}
<Input
name='Conversion Rate'
value={rate}
placeholder='Decimal number - Optional'
onChange={e => addRate(e.target.value)}
/>
No input type number, no keydown just regex
