How can I define type for setState when React.Dispatch<React.SetStateAction<string>> not accepted?
Asked Answered
M

3

81

I have a React DatePicker component with an input element. In order to handle the onChange event, I have onChangeHandler function defined. However, when I want to define the types of all the functions passed down as parameters in the onChangeHandler I get the following error:

Argument of type '(value: string) => void' is not assignable to parameter of type 'Dispatch<SetStateAction>'. Types of parameters 'value' and 'value' are incompatible. 
Type 'SetStateAction' is not assignable to type 'string'. Type '(prevState: string) => string' is not assignable to type 'string'.ts(2345

This error disappears when I define the function as any, but of course we don't want any in the code :).

Below is my setup. I have an input component named Datepicker in my main app that has gets a state from the main app.

const [value, setValue] = useState('');

It gets passed down as props in to a DatePicker component as such:

return (
 <form>
  <label htmlFor='date-picker-input'>Date:</label>
  <br />
  **
  <DatePicker
   value={value}
   setValue={setValue}
   dateFormat='YYYY/MM/DD'
  />
  **
  <button
   type='submit'
   value='Submit'>
   Submit
  </button>
 </form>
)

The DatePicker component looks something like this:

import onChangeHandler from '../utility/onChangeHandler'

interface IDatePickerProps {
 applicationMode?: boolean
 value: string
 setValue: (value: string) => void
 dateFormat: DateFormat
}
const DatePicker: React.FC<IDatePickerProps> = (props) => {
 const {value, setValue, dateFormat} = props
 const applicationMode = props.applicationMode ? true : false
 const [showCalendar, setShowCalendar] = useState(false)
 const [errorMessage, setErrorMessage] = useState('')
 const [clickedDate, setClickedDate] = useState<IClickedDate>({})
 const [dateObject, setDateObject] = useState<IDateObject>({})
 const [isClicked, setIsClicked] = useState<IIsClicked>({})
 //bunch of functions

 return (
  <>
   <div>
    <label htmlFor='date-picker-input aria-label=`enter date in the following format`'>
     {dateFormat}
    </label>
    <button>
     <CalendarIcon />
    </button>
    <input
     id='date-picker-input'
     type='text'
     value={value}
     onChange={(e) =>
      onChangeHandler(
       e,
       dateFormat,
       setValue,
       setErrorMessage,
       setClickedDate,
       setIsClicked
      )
     }
    />
   </div>
   <div>
    <MonthPicker />
    <table>
     <DaysHeading />
     <DatesOfMonth />
    </table>
   </div>
  </>
 )
}

Here is how the onChangeHandler is defined and setValue is used:

const onChangeHandler = (
 event: React.ChangeEvent<HTMLInputElement>,
 dateFormat: string,

 //line causing the error is here:
 setValue: React.Dispatch<React.SetStateAction<string>>,

 setErrorMessage: React.Dispatch<React.SetStateAction<string>>,
 setClickedDate: React.Dispatch<React.SetStateAction<IClickedDate>>,
 setIsClicked: React.Dispatch<React.SetStateAction<IIsClicked>>
): void => {
 const value = event.target.value
 setValue(value)
 let date = ''
 let month = ''
 let year = ''
 let dateFormatCheck
 let dateIsValid
 let invalidAt
 const errorNote = 'Please check entered '

 if (value.length === 10) {
  setErrorMessage('')
  if (dateFormat === 'YYYY/MM/DD') {
   dateFormatCheck = moment(value, 'YYYY/MM/DD', true)
   dateIsValid = dateFormatCheck.isValid()

   if (dateIsValid === true) {
    //do some stuff
   } else {
    invalidAt = dateFormatCheck.invalidAt()
    setErrorMessage(errorNote + errorDefinition(invalidAt))
   }
  }
 }
}
//some other validators and no return value
export default onChangeHandler
Monkfish answered 21/1, 2021 at 8:44 Comment(0)
S
195

You should set type of setValue inside IDatePickerProps to:

setValue : React.Dispatch<React.SetStateAction<string>>

Or change setValue inside onChangeHandler to:

setValue: (value: string) => void;
Scanties answered 21/1, 2021 at 9:6 Comment(0)
G
7
setValue : React.Dispatch<React.SetStateAction<any>>

you need to figure out which type is your data and change it instead of any

Grebe answered 27/6, 2023 at 10:32 Comment(0)
L
-2

My solution for this (I think it is more readable):
In the IDatePickerProps

  setValue: (setValueFunc: (value: string) => void) => void;
Lager answered 23/8, 2022 at 12:26 Comment(2)
and how to know what is dispatch and what I set action?Grebe
It's not more readable for TypeScript, so it will throw an error.Banal

© 2022 - 2024 — McMap. All rights reserved.