reduce takes its result type from the initial value, and {} or [] alone gives you a type that's too narrow. {} as Record<string, number> fixes that, but an assertion also accepts a value that doesn't fit the type. reduce<Record<string, number>>(..., {}) gives you the same result type, and TypeScript still checks the initial value against it.
Only arrays and tuples are checked. If the value can't be assigned to the asserted type, you need the assertion and the call is left alone.
--fix moves the type from the assertion to the call.
Configure
Off by default. This rule needs types, so turning it on makes bun lint type check your code first.
[lint.rules]
"@typescript-eslint/prefer-reduce-type-parameter" = "error" # or "warn"
Examples
Reported:
function count(words: string[]) {
return words.reduce((counts, word) => {
counts[word] = (counts[word] ?? 0) + 1;
return counts;
}, {} as Record<string, number>);
}
function lengths(words: string[]) {
return words.reduce((result, word) => result.concat(word.length), [] as number[]);
}
Not reported:
function count(words: string[]) {
return words.reduce<Record<string, number>>((counts, word) => {
counts[word] = (counts[word] ?? 0) + 1;
return counts;
}, {});
}
function lengths(words: string[]) {
return words.reduce<number[]>((result, word) => result.concat(word.length), []);
}
Here {} isn't a valid Summary, so moving the type would be a type error:
interface Summary {
longest: string;
}
function summarize(words: string[]) {
return words.reduce((summary, word) => {
summary.longest = word;
return summary;
}, {} as Summary);
}