Typesafe: Is there any better way to write this code?

I always try to get better at coding and a challenge I recently came across is this one: I receive some values from database, give that object to a function, which calculates some additional values and adds them to the object. I am aware of two ways to do this. The first is using spread operator - which is very handy, but produces (to my understanding) potentially a huge performance impact because every input object gets copied to be spread.
function calculateSums(project: InputProject)
const budgetEuros = project.workstreams.reduce((acc: number, workstream) => acc + workstream.budgetEuros, 0);
return {
...project,
budgetEuros
}
function calculateSums(project: InputProject)
const budgetEuros = project.workstreams.reduce((acc: number, workstream) => acc + workstream.budgetEuros, 0);
return {
...project,
budgetEuros
}
I tried to avoid this but ended up with a huge amount of code just to satisfy typescript.
type InputProject = Awaited<ReturnType<typeof fetchProjects>>[number];
type OutputProject = InputProject & {
budgetUsedHours: number;
};
type OptionalProject = InputProject & {
budgetUsedHours?: number;
};

function calculateSums(project: InputProject): OutputProject {
const p = project as unknown as OptionalProject;

p.budgetUsedHours= p.workstreams.reduce((acc: number, workstream) => acc + workstream.budgetHours, 0);

return p as unknown as OutputProject;
}
type InputProject = Awaited<ReturnType<typeof fetchProjects>>[number];
type OutputProject = InputProject & {
budgetUsedHours: number;
};
type OptionalProject = InputProject & {
budgetUsedHours?: number;
};

function calculateSums(project: InputProject): OutputProject {
const p = project as unknown as OptionalProject;

p.budgetUsedHours= p.workstreams.reduce((acc: number, workstream) => acc + workstream.budgetHours, 0);

return p as unknown as OutputProject;
}
Is there any better way to write this code?
4 Replies
clar1k
clar1k5d ago
the simpler the better. first option is dope
zebwd
zebwd5d ago
I go by the idea that performance shouldn't be a worry until it actually becomes a problem, don't fall for premature optimization. Because most of the time for operations like your example the performance impact is negligible. You could run some benchmarks and see the difference and then use your criteria to choose one option or another. Otherwise the more readable the better so option 1 is fine
zebwd
zebwd5d ago
But also your second function could be written like this and make typescript happier
function calculateSums<T extends {workstreams: {budgetHours: number}[] }>(project: T): T & {budgetUsedHours: number} {

return Object.assign(project, {budgetUsedHours: project.workstreams.reduce((acc: number, workstream) => acc + workstream.budgetHours, 0)})
}
function calculateSums<T extends {workstreams: {budgetHours: number}[] }>(project: T): T & {budgetUsedHours: number} {

return Object.assign(project, {budgetUsedHours: project.workstreams.reduce((acc: number, workstream) => acc + workstream.budgetHours, 0)})
}
TS playground demo
TS Playground - An online editor for exploring TypeScript and JavaS...
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
Xanacas
XanacasOP5d ago
Thanks to both of you @clar1k @zebwd ! I'll go for option 1 in the feature (as in the past ;P ) I was just very curious, if there is a way that I don't see (sometimes the solution is so obvious that we can't see it).

Did you find this page helpful?