You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 10:01:24