prefer-ts-extras-object-map-values
Prefer objectMapValues from ts-extras over key-preserving objectFromEntries(objectEntries(...).map(...)) chains.
This rule lives only in the experimental preset and reports without autofixing.
Targeted pattern scopeโ
This rule focuses on ts-extras entry pipelines whose callback preserves the original key and only changes the value.
objectFromEntries(objectEntries(value).map(([key, item]) => [key, nextValue]))- the same shape with a block body that immediately returns
[key, nextValue]
It intentionally skips broader patterns that can encode different intent.
What this rule reportsโ
This rule reports ts-extras object remapping chains when all of the following are true:
- the outer call is
objectFromEntries(...) - the inner source is
objectEntries(...) - the intermediate step is a direct
.map(...)call - the callback is an arrow function with a strict
[key, value]tuple parameter - the callback returns a two-item tuple whose first item is the original
key
The rule is currently report-only. It does not autofix or suggest a replacement yet.
Why this rule existsโ
objectMapValues reduces noise in a common value-only remapping pattern.
- The callback contract matches the intent directly:
(value, key) => nextValue. - Readers do not need to mentally unpack an entries pipeline to see that keys stay the same.
- The code avoids a temporary array of tuples in authored source.
Because this pattern appears in semantically different forms, the rule stays narrow on purpose and reports only equivalent key-preserving remaps.
โ Incorrectโ
import {objectEntries, objectFromEntries} from "ts-extras";
const statusById = {
alpha: "up",
beta: "down",
} as const;
const labels = objectFromEntries(
objectEntries(statusById).map(([key, value]) => [key, `${key}:${value}`])
);
โ Correctโ
import {objectMapValues} from "ts-extras";
const statusById = {
alpha: "up",
beta: "down",
} as const;
const labels = objectMapValues(
statusById,
(value, key) => `${key}:${value}`
);
Behavior and migration notesโ
- This rule only reports chains that preserve the original key unchanged.
- It ignores native
Object.entries/Object.fromEntriespipelines to avoid overlapping with the stableobjectEntriesandobjectFromEntriesadoption rules. - It ignores
.map(...)calls that pass athisArg, becauseobjectMapValuesdoes not have an equivalent callback binding parameter. - It ignores function-expression callbacks for now, because the experimental rule avoids assuming
thisbehavior is irrelevant.
Additional examplesโ
โ Incorrect โ Additional exampleโ
import {objectEntries, objectFromEntries} from "ts-extras";
const statusById = {
alpha: "up",
beta: "down",
} as const;
const uppercased = objectFromEntries(
objectEntries(statusById).map(([key, value]) => [key, value.toUpperCase()])
);
โ Correct โ Additional exampleโ
import {objectMapValues} from "ts-extras";
const statusById = {
alpha: "up",
beta: "down",
} as const;
const uppercased = objectMapValues(statusById, (value) => value.toUpperCase());
ESLint flat config exampleโ
import typefest from "eslint-plugin-typefest";
export default [typefest.configs.experimental];
When not to use itโ
Disable this rule if your team prefers explicit entry-tuple pipelines for readability, or if the remapping logic changes keys often enough that objectMapValues is not the dominant style.
Package documentationโ
ts-extras package documentation:
Source file: source/object-map-values.ts
import {objectMapValues} from "ts-extras";
const object = {a: 1, b: 2, c: 3};
const mapped = objectMapValues(object, value => String(value));
//=> {a?: string; b?: string; c?: string}
Rule catalog ID: R086