Description
TypeScript Version: 3.9.2/3.8.3/Nightly
Search Terms:
- array reduce
- reduce type inference
Code
type SomeParamType = { hello: string; world: string; }
function brokenInference<T>(someArg: SomeParamType): boolean {
type KeyType = keyof typeof someArg
const keys = (Object.keys(someArg) as KeyType[])
return keys.reduce((previousValue, currentValue) => {
const result = currentValue == 'hello world'
return previousValue && result
}, true)
}
function correctInference(someArg: SomeParamType): boolean {
type KeyType = keyof typeof someArg
const keys = (Object.keys(someArg) as KeyType[])
return keys.reduce<boolean>((previousValue, currentValue) => {
const test = someArg[currentValue] === 'hello world'
return previousValue && test
}, true)
}
function correctInference1(someArg: SomeParamType): boolean {
type KeyType = keyof typeof someArg
const keys = (Object.keys(someArg) as KeyType[])
const value = keys.reduce((previousValue, currentValue) => {
const test = someArg[currentValue] === 'hello world'
return previousValue && test
}, true)
return value
}
Expected behavior:
The type of keys.reduce(...)
should be inferred as boolean
Actual behavior:
The type of keys.reduce(...)
is inferred as keyof T
.
Notes
From what I can tell, there are currently 3 definitions for Array.reduce
.
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T;
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T, initialValue: T): T;
reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U;
When the reduce
function is called from const result = (item: T) => keys.reduce
TS appears to be inferring the signature of reduce to be reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U;
. When the function is inlined, the signature of reduce
is inferred to be reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T, initialValue: T): T;
.
Question:
Is this signature needed?
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T, initialValue: T): T
This signature would seem to satisfy those constraints.
reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U
Playground Link:
3.9.2
3.8.3
Nightly
Related Issues:
This issue appears to be similar to #33886, #25454, #33886, #29604