React TypeScript属性类型不兼容:string无法赋值给Date问题排查
问题原因与优化方案
问题原因
这段代码在TypeScript中报错的核心是类型不匹配:
allEvents的类型从初始数组events自动推断为{ title: string; start: Date; end: Date; }[],要求每个元素的start和end必须是Date类型。- 但
newEvent的初始状态设置为{ title: "", start: "", end: "" },TypeScript会推断它的类型为{ title: string; start: string; end: string; },其中start和end是字符串类型。
当执行handleAddEvent将newEvent添加到allEvents时,TypeScript检测到两种类型无法兼容,因此抛出错误:
const allEvents: { title: string; start: Date; end: Date; }[] Type '{ title: string; start: Date; end: Date; } | { title: string; start: string; end: string; }' is not assignable to type '{ title: string; start: Date; end: Date; }'. Type '{ title: string; start: string; end: string; }' is not assignable to type '{ title: string; start: Date; end: Date; }'. Types of property 'start' are incompatible. Type 'string' is not assignable to type 'Date'
JavaScript无强类型校验,所以类似写法不会报错,但TypeScript会严格校验类型一致性。
优化方案
1. 定义统一的事件类型接口
先明确事件的类型,避免自动推断带来的类型不一致:
interface IEvent { title: string; start: Date; end: Date; }
2. 修正newEvent的初始状态与类型
将newEvent的start和end初始值改为Date类型,并显式指定类型为IEvent:
const [newEvent, setNewEvent] = React.useState<IEvent>({ title: "", start: new Date(), end: new Date() });
3. 补充日期输入的类型转换(必要扩展)
当前代码仅实现了标题输入,后续添加日期输入框时,需要将用户输入的字符串日期转换为Date类型,示例:
<input type="datetime-local" onChange={(e) => setNewEvent({ ...newEvent, start: new Date(e.target.value) })} />
完整优化后的代码
export interface IMeetingRoomBookingProps { description: string; } // 新增事件类型接口 interface IEvent { title: string; start: Date; end: Date; } moment.tz.setDefault('Europe/Paris') const localizer = momentLocalizer(moment) // 指定events的类型为IEvent[] const events: IEvent[] = [ { title: "Store mødelokale", start: new Date(2022, 10, 3, 7, 30), end: new Date(2022, 10, 3, 8, 20), }, { title: "Lille mødelokale", start: new Date(2022, 10, 3, 8, 30), end: new Date(2022, 10, 3, 10, 0), }, { title: "Lille mødelokale", start: new Date(2022, 10, 4, 8, 30), end: new Date(2022, 10, 4, 11, 0), }, { title: "Mødelokale Vest", start: new Date(2022, 10, 5, 7, 40), end: new Date(2022, 10, 5, 13, 15), }, ] const MeetingRoomBooking = ({ description }: IMeetingRoomBookingProps) => { // 修正newEvent的类型和初始值 const [newEvent, setNewEvent] = React.useState<IEvent>({ title: "", start: new Date(), end: new Date() }); // 显式指定allEvents的类型 const [allEvents, setAllEvents] = React.useState<IEvent[]>(events); const handleAddEvent = () => { setAllEvents([...allEvents, newEvent]) } return ( <div className={styles.parent}> <h1>Calendar</h1> <h2>Add New Event</h2> <div> <input type="text" onChange={(e) => setNewEvent({ ...newEvent, title: e.target.value })} placeholder='Add Title' style={{ width: "20%", marginRight: "10px" }} /> {/* 新增日期输入框示例 */} <input type="datetime-local" onChange={(e) => setNewEvent({ ...newEvent, start: new Date(e.target.value) })} /> <input type="datetime-local" onChange={(e) => setNewEvent({ ...newEvent, end: new Date(e.target.value) })} /> <button onClick={handleAddEvent}>添加事件</button> </div> <div className={styles.calendar}> <Calendar defaultView='week' localizer={localizer} events={allEvents} startAccessor="start" endAccessor="end" selectable style={{ height: 1050, width: 1050, margin: "50px" }} /> </div> </div> ) } export default MeetingRoomBooking
内容的提问来源于stack exchange,提问作者liondepierre
相关产品推荐
相关产品推荐

