I have weakly/implicit data structure as input and want to convert it into a more strict/explicit structure.
Take as simplified example a time tracking system where a numeric value of worked hours is mapped for each day of the week. So we have Monday 8 hours, Tuesday 3 hours, ….
The input type is just an Array of integers. For the internal representation I‘ve the following types:
const WEEKDAYS = [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ] as const;
type Weekday = typeof WEEKDAYS[number];
type TrackedHours = Record<Weekday, number>;
The approach to use a const array to infer the type from is already a preparation for my current solution approach later.
So I want to write a function which converts from the input data of an array to this structure.
declare function parseTrackedHours(data: number[]): TrackedHours;
Taking into account scenarios with more lengthy type unions (e.g. days of a month), I would like to write a (functional?) algorithm to do the job. With plain JavaScript, a reduce comes into my mind:
function parseTrackedHours(data: number[]): TrackedHours {
return WEEKDAYS.reduce(
(trackedHours, weekday, index) => ({
[weekday]: data[index] ?? 0,
...trackingHours,
}),
{},
);
}
This works fine from an algorithmic point of view and I’m pretty happy with that. But it doesn’t work in terms of inferred types by the compiler. Because the initial {}
is not of type TrackedHours
. I could do a simple type-cast to make the compiler accept it. But casting the initial value of the reduce function makes the whole accumulator function not type-safe. So I can make any stupid mistake in the implementation (especially for more complicated cases than the one above) or change something about the outer type-system and it would be just fine during compile-time. So I would prefer to not type-cast the initial value here.
But maybe this approach is the wrong direction anyhow. Could someone show me a type-safe algorithm for the above example?
1