5

Working on an update to Replace Moment.js with date-fns for Ant Design's DatePicker based on the documentation which seems to be working fine.

Mainly it's suggesting to create the following:

import dateFnsGenerateConfig from 'rc-picker/lib/generate/dateFns'
import generatePicker from 'antd/es/date-picker/generatePicker'

const DatePicker = generatePicker<Date>(dateFnsGenerateConfig)

Then use the component as below:

<DatePicker.RangePicker
          placeholder={['From', 'To']}
          onChange={range => setRange(range)}
          value={range}
/>

For the above the following state has been created with the type RangeValue:

const [range, setRange] = useState<RangeValue<Date>>(
   [from, to]
)

The RangeValue type has been imported as the following:

import { RangeValue } from 'rc-picker/lib/interface'

// technically:
// import { RangeValue } from '../../../../node_modules/rc-picker/lib/interface'

Question:

I found only this comment in one of the questions here where we have similar conversation.

Is there any way to import the RangeValue type, maybe from Ant Design? Thank you!

norbitrial
  • 14,716
  • 7
  • 32
  • 59

2 Answers2

4

I was having a hard time typing antd values. Seems like they don't provide any easy option. Eventually ended up on using this:

type RangeValue = Parameters<NonNullable<React.ComponentProps<typeof DatePicker.RangePicker>['onChange']>>[0]

That will pull out the type of the first argument that is sent into the onChange function. It will also work with other events (onClick, onBlur etc). You can also pull out the types of other arguments simply by increasing the number in the square brackets. Now you can assign this type to your onChange handler:

const handleOnChange = (dates: RangeValue, formattedDates: string[]) => {
//do something
return dates 
}
1

Unfortunately, in the response from @mateusz-bacherycz, the types are defined as "any," which leads to the loss of TypeScript support.

The types are defined here: rc-picker/lib/interface.d.ts

Just add the lines to fit your needs:

// copied from rc-picker/lib/interface.d.ts
declare type EventValue<DateType> = DateType | null;
declare type RangeValue<DateType> = [EventValue<DateType>, EventValue<DateType>] | null;

Usage:

const handleOnChange = (dates: RangeValue, formattedDates: string[]) => {
  //do something
  return dates 
}

If you would like to use the range picker in your form and retrieve the values as strings, this is what i use:

import dayjs, {Dayjs} from "dayjs";
import React from "react";
import {RangePickerDateProps} from "antd/es/date-picker/generatePicker";
import {DatePicker} from "antd";

export const DISPLAY_DATE = 'DD.MM.YYYY'
export const SERVER_DATE_FORMAT = "YYYY-MM-DD"

// copied from rc-picker/lib/interface.d.ts
declare type EventValue<DateType> = DateType | null;
declare type RangeValue<DateType> = [EventValue<DateType>, EventValue<DateType>] | null;

const datePickerValue = (value: RangeValue<string> | undefined): RangeValue<Dayjs> | undefined => {
    if (value == undefined) return value
    if (value[0] == undefined || value[1] == undefined) return undefined
    return [dayjs(value[0]), dayjs(value[1])]
}

const FormDateRangePicker: React.FC<RangePickerDateProps<string>> = ({...props}) => {
    const {value, onChange, ...remainingProps} = props

    const onChangeHandler = (value: RangeValue<Dayjs> | undefined, formatString: [string, string]) => {
        const from = value?.[0]?.format(SERVER_DATE_FORMAT) ?? null
        const to = value?.[1]?.format(SERVER_DATE_FORMAT) ?? null
        onChange?.([from, to], formatString)
    }

    return <DatePicker.RangePicker style={{width: "100%"}}
                                   {...remainingProps as RangePickerDateProps<Dayjs>}
                                   format={DISPLAY_DATE}
                                   value={datePickerValue(value)}
                                   onChange={onChangeHandler}
    />
}

export default FormDateRangePicker
mleister
  • 1,697
  • 2
  • 20
  • 46