Aller au contenu principal

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.

remarque

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

evolvemapValues
Applies toSpecific keysAll keys
PreservesUntransformed keysN/A
NestedSupportedManual

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>

Type

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>

Type

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