evolve()
evolve<
T,Tr>(object,transformations): Evolved<T,Tr>
Applies transformations to an object in a declarative way.
π Why is this a Hidden Gem?
A distinctively declarative way to transform object properties using functions.
Properties without transformations are preserved.
Type Parametersβ
T: T extends Record<string, unknown>β
The type of the input object.
Tr: Tr extends Transformations<T>β
The type of the transformations object.
Parametersβ
object: Tβ
The object to transform.
transformations: Trβ
Object mapping property names to transformation functions.
Returns: Evolved<T, Tr>β
A new object with transformed values.
Sinceβ
2.0.0
Noteβ
Transformations for non-existent properties are ignored.
Noteβ
Supports symbol keys via Reflect.ownKeys.
Performanceβ
O(n) time & space where n is number of properties.
Also known asβ
evolve (Remeda, Ramda) Β· β (Lodash, es-toolkit, Radashi, Effect, Modern Dash, Antfu)
Exampleβ
const user = { count: 1, name: 'tom', active: true };
evolve(user, { count: (x) => x + 1, name: (s) => s.toUpperCase() });
// => { count: 2, name: 'TOM', active: true }
// Nested transformations
evolve(
{ profile: { firstName: 'john', age: 25 } },
{ profile: { firstName: (s) => s.toUpperCase(), age: (n) => n + 1 } }
);
// => { profile: { firstName: 'JOHN', age: 26 } }
How it works?β
Applies transformations to an object in a declarative way. Properties without transformations are preserved unchanged.
Nested Transformationsβ
evolve vs mapValuesβ
| evolve | mapValues | |
|---|---|---|
| Applies to | Specific keys | All keys |
| Preserves | Untransformed keys | N/A |
| Nested | Supported | Manual |
Use Casesβ
Transform specific fields πβ
Apply different transformation functions to specific keys in an object. Perfect for normalizing data from API responses.
const user = evolve(apiResponse, {
name: (s) => s.trim(),
age: (n) => Number(n),
});
Apply nested transformationsβ
Declaratively transform deeply nested properties. Essential for modifying complex state trees.
const state = evolve(appState, {
settings: {
theme: (t) => t.toLowerCase(),
notifications: (n) => !n // Toggle boolean
}
});
Sanitize data conditionallyβ
Apply transformation logic that adapts to values. Useful for data cleaning pipelines.
const cleaned = evolve(data, {
score: (n) => (n < 0 ? 0 : n), // Clamp to 0
tags: (arr) => arr.filter(t => t.length > 0) // Remove empty tags
});
Normalize i18n translation entriesβ
Clean up translation strings loaded from external sources. Essential for i18n pipelines where translations may have inconsistent formatting.
const rawTranslation = {
greeting: " Hello, World! ",
farewell: " Goodbye ",
error: " SOMETHING WENT WRONG ",
};
const cleaned = evolve(rawTranslation, {
greeting: (s) => s.trim(),
farewell: (s) => s.trim(),
error: (s) => s.trim().toLowerCase(),
});
// => { greeting: "Hello, World!", farewell: "Goodbye", error: "something went wrong" }
Transform tree node properties for renderingβ
Transform raw tree data into renderable node objects declaratively. Essential for tree components that need computed display properties.
const rawNode = {
name: "components",
childCount: 12,
type: "directory",
depth: 2,
};
const renderNode = evolve(rawNode, {
name: (n) => `π ${n}`,
childCount: (c) => `(${c} items)`,
depth: (d) => d * 24, // Convert to pixel indentation
});
// => { name: "π components", childCount: "(12 items)", type: "directory", depth: 48 }
Adapt overlay position for RTL layoutsβ
Transform overlay position properties when switching between LTR and RTL. Critical for design systems supporting bidirectional text.
const ltrPosition = {
left: 100,
right: "auto",
transformOrigin: "top left",
};
const toRTL = evolve(ltrPosition, {
left: () => "auto",
right: (r) => (r === "auto" ? 100 : r),
transformOrigin: (o) => o.replace("left", "right"),
});
// => { left: "auto", right: 100, transformOrigin: "top right" }
Transform design tokens for CSS outputβ
Convert raw design token values into CSS-ready formats. Perfect for design system build pipelines generating CSS custom properties.
const tokens = {
spacing: 8,
fontSize: 16,
borderRadius: 4,
opacity: 0.85,
};
const cssTokens = evolve(tokens, {
spacing: (n) => `${n}px`,
fontSize: (n) => `${n}px`,
borderRadius: (n) => `${n}px`,
opacity: (n) => String(n),
});
// => { spacing: "8px", fontSize: "16px", borderRadius: "4px", opacity: "0.85" }
Evolved<T, Tr>β
Evolved<
T,Tr> ={ [K in keyof T]: K extends keyof Tr ? Tr[K] extends (value: T[K]) => infer R ? R : Tr[K] extends Record<string, unknown> ? T[K] extends Record<string, unknown> ? Evolved<T[K], Tr[K]> : T[K] : T[K] : T[K] }
Type representing the result of applying transformations to an object.
Type Parametersβ
T: Tβ
Tr: Trβ
Sinceβ
2.0.0
Transformations<T>β
Transformations<
T> = { [K in keyof T]?: T[K] extends (args: unknown[]) => unknown ? (value: T[K]) => unknown : T[K] extends Record<string, unknown> ? Transformations<T[K]> | ((value: T[K]) => unknown) : (value: T[K]) => unknown }
Type representing transformation functions for each property.
Type Parametersβ
T: Tβ
Sinceβ
2.0.0