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
});
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