How I stopped maintaining hundreds of lines of mapping objects and started writing functions that derive the output instead.

You've probably seen code like this everywhere:
export const SECTION_MAPPING: Record<Section, string> = {
community: "Community",
engineering: "Engineering",
customers: "Customers",
projects: "Projects",
"open-source": "Open Source"
};
At first glance, nothing wrong with it.
But in real codebases this ends up turning into hundreds of lines of hand-written mappings.
And the weird part is: most of them follow the same pattern.
Look at the transformation:
projects -> Projectsopen-source -> Open Sourceuser_profile -> User ProfileIt's always the same idea:
- or _)So why are we writing the output instead of the rule?
Instead of maintaining a mapping:
SECTION_MAPPING["open-source"];
Just derive it:
export function formatLabel(input: string): string {
return input
.replace(/[-_]/g, " ").split(" ")
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(" ");
}
Now the mapping disappears completely:
formatLabel("open-source"); // Open Source
No data file. No duplication. Just logic.
Real systems always introduce "special cases":
And this is where people usually go back to object mappings:
const EXCEPTIONS: Record<string, string> = {
ai: "AI",
sdk: "SDK",
mcp: "MCP",
waf: "WAF"
};
But that's still just encoding a simple rule in a verbose way.
These aren't really exceptions. They're just "always uppercase words".
So instead of mapping key -> value, just store intent:
const UPPERCASE_WORDS = ["ai", "sdk", "mcp", "waf"];
Now the function becomes:
export function formatLabel(input: string): string {
return input.replace(/[-_]/g, " ").split(" ")
.map(word => {
const lower = word.toLowerCase();
if (UPPERCASE_WORDS.includes(lower)) return lower.toUpperCase();
return word.charAt(0).toUpperCase() + word.slice(1);
}).join(" ");
};
Not much in code size.
A lot in design.
Before:
After:
Here's the thing I keep coming back to:
Most mapping objects aren't data. They're failed functions.
I mean that in the most practical sense possible. You already know how to transform open-source into Open Source. You've done it a thousand times. The only reason you're storing it in an object is because at some point someone decided "this is data, not logic."
But it doesn't have to be either/or.
Once this clicked for me, I started seeing it everywhere. The sidebar labels that don't match their routes. The permission names that get transformed into readable text. The feature flags that are just camelCase in, Title Case out.
The best part? You don't even need to refactor everything. Just next time you reach for a mapping object, ask yourself: what's the rule here?
Chances are, you already know it.
Learn more about my work and projects!