TypeScript
@calendarjs/react ships first-class TypeScript types — no @types/* install needed.
The package distinguishes two type shapes per component:
- Input shape —
Schedule.EventInput,Timeline.ItemInput. Loose: only the truly required field is mandatory; everything else is optional. The component fills in defaults (guid,title,color,type, ...) on render. Includes an index signature so you can attach app metadata without casts. - Resolved shape —
Schedule.Event,Timeline.Item. Strict: whatgetData()returns and what callbacks likeonCreate/onChangeEventhand back, with all defaults filled in.
This split is the same pattern React uses for CSSProperties and Next.js uses for route handler params: user provides loose, framework hands back strict.
Importing the type namespaces
Section titled “Importing the type namespaces”import { Schedule, Timeline, Calendar } from '@calendarjs/react';
import type {
Schedule as ScheduleNS,
Timeline as TimelineNS,
Calendar as CalendarNS,
} from '@calendarjs/react';
Each *NS import gives you access to the namespace members (Event, EventInput, Options, Instance, etc.) under the same name. The runtime imports (Schedule, Timeline, Calendar) remain the React component values.
Input vs resolved — Schedule
Section titled “Input vs resolved — Schedule”import type { Schedule as ScheduleNS } from '@calendarjs/react';
// ✅ Loose input — only `start` is required.
const minimal: ScheduleNS.EventInput = { start: '09:00' };
// ✅ App-specific metadata is allowed via index signature, no `as any`.
const enriched: ScheduleNS.EventInput = {
start: '09:00',
end: '10:00',
class_id: 42,
teacher_id: 7,
};
// `Event` (resolved) requires guid/title/color/type — typically you receive
// these from callbacks rather than constructing them yourself.
function logEvent(ev: ScheduleNS.Event) {
console.log(ev.guid, ev.title, ev.color);
}
Input vs resolved — Timeline
Section titled “Input vs resolved — Timeline”import type { Timeline as TimelineNS } from '@calendarjs/react';
// ✅ Only `date` is required on input.
const items: TimelineNS.ItemInput[] = [
{ date: '2025-01-15' },
{ date: '2025-02-01', title: 'Milestone 1' },
{ date: '2025-03-01', id: 42, status: 'done' }, // app metadata is fine
];
Typed refs
Section titled “Typed refs”Use useRef<NS.Instance>(null) instead of useRef<any> to get full method autocomplete:
import { useRef } from 'react';
import { Schedule } from '@calendarjs/react';
import type { Schedule as ScheduleNS } from '@calendarjs/react';
export default function App() {
const ref = useRef<ScheduleNS.Instance>(null);
const addOne = () => {
// Fully typed — autocompletes addEvents, getData, undo, etc.
ref.current?.addEvents([{ start: '09:00', end: '10:00' }]);
};
return <Schedule ref={ref} data={[]} />;
}
The hooks (useSchedule, useTimeline, useCalendar) are pre-typed — no annotation needed:
import { useSchedule } from '@calendarjs/react';
const { ref, instance } = useSchedule();
// ^ (instance: ScheduleNS.Instance | null) => void
// ^ ScheduleNS.Instance | null
Callback signatures
Section titled “Callback signatures”onCreate and onBeforeCreate always receive an array (length ≥ 1) — no union, no Array.isArray unwrap:
import { Schedule } from '@calendarjs/react';
import type { Schedule as ScheduleNS } from '@calendarjs/react';
const onCreate = (events: ScheduleNS.Event[]) => {
events.forEach((ev) => console.log(ev.guid));
};
const onBeforeCreate = (events: ScheduleNS.Event[]): boolean | void => {
if (events.some((ev) => ev.start < '09:00')) return false; // cancel
};
<Schedule onCreate={onCreate} onBeforeCreate={onBeforeCreate} data={[]} />
Per-event callbacks (onEdition, onDblClick, onDelete, onChangeEvent) receive a single resolved Event:
const onChangeEvent = (
event: ScheduleNS.Event,
oldValue: Partial<ScheduleNS.Event>,
newValue: Partial<ScheduleNS.Event>,
) => {
console.log(`Event ${event.guid}: changed from`, oldValue, 'to', newValue);
};
Method signatures
Section titled “Method signatures”The instance methods accept loose input types (so consumers can pass app metadata) and return resolved types:
import type { Schedule as ScheduleNS } from '@calendarjs/react';
const ref = useRef<ScheduleNS.Instance>(null);
// addEvents accepts EventInput | EventInput[] (loose), returns Event[] (resolved).
const created: ScheduleNS.Event[] | false | undefined =
ref.current?.addEvents([{ start: '09:00', class_id: 42 }]);
// updateEvent accepts Partial<EventInput> for `newValue`.
ref.current?.updateEvent('guid-1', { title: 'New title', class_id: 99 });
// setData accepts EventInput[].
ref.current?.setData([{ start: '09:00', class_id: 42 }]);
// getData returns Event[] (resolved).
const all: ScheduleNS.Event[] | undefined = ref.current?.getData();
Strongly-typed app metadata (advanced)
Section titled “Strongly-typed app metadata (advanced)”The index signature on EventInput accepts any keys, but loses type safety for those keys. To keep your app metadata fully typed, intersect with a domain interface:
import type { Schedule as ScheduleNS } from '@calendarjs/react';
interface ClassMeta {
class_id: number;
teacher_id: number;
room: string;
}
type ClassEvent = ScheduleNS.EventInput & ClassMeta;
const events: ClassEvent[] = [
{ start: '09:00', end: '10:00', class_id: 42, teacher_id: 7, room: 'A1' },
// missing class_id would now be a TS error
];
// On the way out, intersect Event with the same metadata.
const onCreate = (created: Array<ScheduleNS.Event & ClassMeta>) => {
created.forEach((ev) => console.log(ev.guid, ev.class_id));
};
Verification
Section titled “Verification”This snippet should compile under strict TS with no casts:
import { useState } from 'react';
import { Schedule, Timeline } from '@calendarjs/react';
import type { Schedule as ScheduleNS } from '@calendarjs/react';
export default function App() {
// Loose input — extra app fields, no cast.
const [events, setEvents] = useState<ScheduleNS.EventInput[]>([
{ start: '09:00', end: '10:00', class_id: 42, teacher_id: 7 },
{ start: '10:00', end: '11:00', class_id: 42, teacher_id: 7 },
]);
// Always Event[], no union.
const onCreate = (created: ScheduleNS.Event[]) => {
setEvents((prev) => [...prev, ...created]);
};
// Timeline items with extra `id` field — no cast.
const items = [
{ id: 1, title: 'A', date: '2026-01-01' },
{ id: 2, title: 'B', date: '2026-01-02' },
];
return (
<>
<Schedule data={events} onCreate={onCreate} />
<Timeline data={items} order="asc" />
</>
);
}
Related
Section titled “Related”- Getting Started — first steps with
@calendarjs/react - Hooks —
useCalendar/useSchedule/useTimeline - Schedule / Calendar / Timeline — per-component docs