Say I've got these types defined:
export type Event = {
name: EventName,
timestamp: Timestamp,
};
export type EventWithMetadata = Event & {
deviceId: ID,
};
I'm looking to define a common function interface like so:
export type SideEffect = (event: Event, run?: Run) => Partial<Run>;
and using it with this function
// Note: many of these side-effect functions exist, with multiple specializations of the base Event
// type as potential arguments. This is just one example.
const updateTiming: SideEffect = (event: EventWithMetadata, run) => {
log.debug('updateTiming: %j', event);
return {
lastUpdated: event.timestamp,
deviceId: event.deviceId,
};
};
but then I hit this error:
error TS2322: Type '(event: EventWithMetadata, run: Run | undefined) => { startTime: number; deviceId: string; }' is not assignable to type 'SideEffect'.
Types of parameters 'event' and 'event' are incompatible.
Type 'Event' is not assignable to type 'EventWithMetadata'.
Property 'deviceId' is missing in type 'Event' but required in type '{ deviceId: string; }'.
which makes sense: Typescript thinks I'm trying to downcast Event
into EventWithMetadata
, which obviously can't happen.
After a lot of searching on generics and overloads and union types, the best answer I could find is this one. I really hate the result and wouldn't want to make it a pattern:
const updateTiming: SideEffect = (inputEvent: Event, run) => {
const event = inputEvent as EventWithMetadata; // <- This sucks.
log.debug('updateTiming: %j', event);
return {
lastUpdated: event.timestamp,
deviceId: event.deviceId,
};
};
Are there better solutions than casting?