The Situation
type Convert<T> = {
[P in keyof T]: T[P] extends string ? number : T[P]
}
function test<T>(target: T): Convert<T> {
return target as any
}
const bar: Bar = test({
a: '', // issue arises here!
b: v => { }
})
In the scenario above, the type checker faces a challenge while inferring the generic type parameter T
based on the argument passed to the function test
. This is primarily due to the presence of a context-sensitive function under property b
, where the callback parameter v
lacks explicit typing, leading to contextual inference requirements. The compiler defers such inference till after determining T
, expecting it to precede the contextual analysis.
Consequently, the type checker opts for an alternate route for inference: the function's return type. It can contextually deduce T
from the anticipated return type of Bar
. This behavior, known as inferring generic function type parameters from the contextual return type, debuted in TypeScript 2.4 following implementation via microsoft/TypeScript#16072.
Using Convert<T>
, a homomorphic mapped type enabling compiler to ascertain T
from
Bar</code by initially assuming that <code>T
equals
Bar
and subsequently verifying this assumption. Although validation succeeds against the expected return type (as
Convert<Bar>
aligns with
Bar
), it fails when applied to the input argument
target
, resulting in an error prompt.
An Alternative Approach
function test<T, R extends Convert<T>>(target: T): R {
return target as any
}
const bar: Bar = test({
a: '', // allowed
b: v => { } // subject to potential errors without proper annotation
})
If we introduce a secondary type parameter R
, the linkage between R
and T
for inference breaks. While R
retains contextual typing from Bar
,
T</code solely relies on the value supplied as <code>target
for deduction. The constraint
R extends Convert<T>
does not offer an inference point for
T
, contrary to an unresolved feature request documented at
microsoft/TypeScript#7234. As a consequence,
R
's determination remains unconnected to
T
. Despite post-inference evaluation checking
R
against
Convert<T>
, there is no impact on the inferred type.
This deliberate usage sometimes impedes inference; a pending feature plea situated at microsoft/TypeScript#14829 advocates means to prevent a type parameter from serving as a generic inference position. While existing solutions suggest introducing an additional type parameter cited in this associated comment on ms/TS#14829.
All considered, with T
confined exclusively to function argument-driven inference and
R</code discerned solely from <code>Bar
, harmony prevails since
Bar
harmonizes with
Convert<T>
, rectifying the
a
error by framing no expectations toward its numeric typing.
Regarding callback parameter v
, discrepancies may arise without defined context prompting implicit tagging as any
. Activation of the --noImplicitAny
compiler option could signal concern here. Alternatively, manual annotation specifies v
as any
` nullifies the initial anomaly through independent T
deduction sans delays.
View code in Playground