Repository navigation
Consider re-ordering Array#reduce overloads in lib.d.ts #7014
Description
Activity
Simpler example:
let arrayOfObjs: {}[] = [/*...*/]; let countOfProps = arrayOfObjs.reduce((sum, obj) => sum + Object.keys(obj).length, 0);
This doesn't compile, tsc reports
"Operator '+' cannot be applied to types '{}' and 'number'".In fact the code is fine and runs fine.
tsc took the first overload since it works with
T={}, so the second (correct) overload is not considered.In general, the second overload will always be skipped if
Uis assignable toT(in this example,numberis assignable to{}).Swapping the order of the two
Array#reduceoverloads inlib.d.tsfixes this.- changed the title
[-]Type inference problem with Array.reduce (lib.d.ts)[/-][+]Consider re-ordering Array#reduce overloads in lib.d.ts[/+]on Feb 11, 2016 RyanCavanaugh commented
on Feb 12, 2016 MemberMore actionsI believe it's safe to do this now -- the order we had was dependent on behavior that is no longer the case (ancient history, see http://typescript.codeplex.com/workitem/2352).
Wow, nice archaeological find 😄 Those were the days...
- addedSuggestionAn idea for TypeScriptAn idea for TypeScriptIn DiscussionNot yet reached consensusNot yet reached consensus
on Feb 16, 2016 aluanhaddad commented
on Mar 11, 2016 ContributorMore actionsGlad this can now be resolved, and I really appreciate the effort the team takes in polishing these corner cases.
As a side not, I really dislike the argument ordering that TC39 chose for
Array.prototype.reduceandArray.prototype.reduceRight. The seed should come first, not just because it makes type inference easier, but because it makes things more readable. Anyway, that decision is ancient history, but I wanted to rant about it.Reacted by Ryan Cavanaugh and AnyhowStepJust stumbled on this - look forward to this being resolved! For anyone else wondering what to do in the interim just supply the type parameter. So to take Troy Gerwien (@yortus) example, this:
let arrayOfObjs: {}[] = [/*...*/]; let countOfProps = arrayOfObjs.reduce((sum, obj) => sum + Object.keys(obj).length, 0);
Becomes:
let arrayOfObjs: {}[] = [/*...*/]; let countOfProps = arrayOfObjs.reduce<number>((sum, obj) => sum + Object.keys(obj).length, 0);
Reacted by Sam Woodard, Derrick Beining, Kevin Rambaud, okmttdhr, tada and R.G.Reacted by jsuryahyd, Diyorbek Sadullaev and R.G.- addedHelp WantedYou can do thisYou can do thisDomain: lib.d.tsThe issue relates to the different libraries shipped with TypeScriptThe issue relates to the different libraries shipped with TypeScriptand removedIn DiscussionNot yet reached consensusNot yet reached consensus
on Jun 9, 2016 RyanCavanaugh commented
on Jun 9, 2016 MemberMore actionsTaking PRs on this with the caveat we're still not 100% sure this is going to be an overall improvement, so reserving the right to reject it if it turns out to be bad on net.
- addedGood First IssueWell scoped, documented and has the green lightWell scoped, documented and has the green light
on Jun 9, 2016 I am on this PR.Reacted by John Reilly and Duncan Mak1 remaining item
Bilal Durrani (@bdurrani) Just noticed that I closed the PR myself. Might had encountered some problem but forgot to update the comment here.
agreed, we encounter this with typescript 3.7.3
const A = [1, '2', 3] const str: string = A.reduce((str, a) => `${str} ${a.toString()}`, '')
which results in this compilation error:
Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'. 2 const str: string = A.reduce((str, a) => `${str} ${a.toString}`, '') ~~~
there is an easy enough workaround for now, i.e.
A.map(_ => _.toString()).reduce(...), but this seems worth fixing?Reacted by Žilvinas and James C. Davisagreed, we encounter this with typescript 3.7.3
const A = [1, '2', 3] const str: string = A.reduce((str, a) => `${str} ${a.toString()}`, '')
which results in this compilation error:
Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'. 2 const str: string = A.reduce((str, a) => `${str} ${a.toString}`, '') ~~~
there is an easy enough workaround for now, i.e.
A.map(_ => _.toString()).reduce(...), but this seems worth fixing?An easier workaround.We provide the generic paramater here, so it matches the second overload.
const A = [1, '2', 3] const str: string = A.reduce<string>((str, a) => `${str} ${a.toString()}`, '')
may be fix this with typescript 4.2.2?
Reacted by Eugene Borys- added 5 commits that reference this issue
on Dec 11, 2025 - added 2 commits that reference this issue
on Jan 29, 2026
Example code:
The call to
Array#reducein the above example definitely returns a unary function, but the type system erroneously infers the return type as a binary function.This seems to be caused by the declaration order of the two overloads of
Array#reduceinlib.d.ts. If the declaration order is reversed, the problem is solved.The two overloaded declarations in
lib.d.tsare as follows:The first overload matches the example with
T=BinaryFunction, since it satisfies the compiler's assignability checks. So the second overload is never considered, even though it is a strictly better match, withT=BinaryFunctionandU=UnaryFunction.Would it be possible to swap the overload order for
Array#reduce(andArray#reduceRight) inlib.d.tsto resolve this issue?