Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect type inference for reduce method accumulator when value is number #58092

Closed
mznx opened this issue Apr 5, 2024 · 2 comments
Closed

Comments

@mznx
Copy link

mznx commented Apr 5, 2024

πŸ”Ž Search Terms

incorrect type inference for reduce

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried

⏯ Playground Link

https://www.typescriptlang.org/play?#code/MYewdgzgLgBAggLhgJQKagE4BMA80MCWYA5gDQxgCuAtgEaoYwA+FlANmwHwwC8MA3gF8A3AChQkWBBoBGXjADytAFbooAOgBuAQzaVUEABRwAlOoyoslYKkOHp1E724OYAahgzyABhNjRAPQBFCAwDBggGBAwAO4EUAAWMPhExDBE6WDxBLoAarr64uDQyTQATPJKqsAaOnoGxmYWVjZ2Dk48LjTunuQA5H1+okA

πŸ’» Code

const A: Record<string, number | null> = {};
const sum1 = Object.values(A).reduce((sum) => sum + 1, 0);
//                                             ^ error: 'sum' is possibly 'null'

// no errors with string in initialValue
const sum2 = Object.values(A).reduce((sum) => sum + 1, '');

πŸ™ Actual behavior

TypeScript incorrectly infers the type of the accumulator in the reduce method as number | null even when the initial value is number.

πŸ™‚ Expected behavior

TypeScript should infer the type of the accumulator the reduce method as number when the initial value is a number.

Additional information about the issue

Explicitly specifying the types resolves the issue, but TypeScript should correctly infer the type without explicit types.

const A: Record<string, number | null> = {};
const sum1 = Object.values(A).reduce((sum: number) => sum + 1, 0);
//                                         ^^^^^^      ^ no errors
@snarbies
Copy link

snarbies commented Apr 5, 2024

It doesn't look like reduce itself is generic. The point of inference is Object.values where it infers T as number | null from Record<string, number | null>, which is correct.

Correction: I missed the third overload, which is generic. It looks like that overload is not being selected here. Probably the first overload (non-generic) is being selected since your arguments are all valid subtypes of the parameter types.

The error goes away if you explicitly call the generic overload.

const sum1 = Object.values(A).reduce<number>((sum) => sum + 1, 0);

@nmain
Copy link

nmain commented Apr 5, 2024

Probably the first overload (non-generic) is being selected since your arguments are all valid subtypes of the parameter types.

That's what's going on. I think the ordering priority of the overloads is justified. If you call reduce with an initialValue that is compatible with the element type of the array, isn't it more likely that you want that element type and not a subtype?

One can easily devise examples of reasonable-looking operations that fail if the overloads are switched: Playground

@mznx mznx closed this as completed Apr 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants