The TypeScript compiler doesn't make use of a generic constraint for inference positioning. Check out this query on Github to delve into this matter further. Essentially, when you invoke t(arr)
, the compiler deduces Src
as number[]
, but it can't leverage the resulting constraint number[] extends A[]
to infer A
. As there are no other cues to infer A
, the process fails and yields an empty type {}
.
To address this issue... it might not be necessary to have dual type parameters. If your goal is for A
to always represent the element type of array Src
, you can simply extract that element type using a lookup of the number
-indexed property type of
Src</code, like this: <code>Src[number]
instead of
A
:
type TTest = <Src extends any[]>(src: Src) => (x: Src[number]) => Src[number]
declare const arr: number[]
declare const t: TTest
t(arr) // const t: <number[]>(src: number[]) => (x: number) => number
This method seems to work effectively. I trust this explanation will be helpful to you. Best wishes!
UPDATE
In light of your updated types, one potential solution involves utilizing conditional types and infer
to derive A
from
Src</code, like so:</p>
<pre><code>type AFromSrc<Src extends TInputs<any>> = Src extends TInputs<infer A> ? A : never;
type TTest = <Src extends TInputs<any>>(src: Src) =>
(x: AFromSrc<Src>) => AFromSrc<Src>
If the compiler can accurately determine A
from TInputs<A>
, this approach should function smoothly. It's crucial to ensure that TInputs<>
provides enough transparency for the inference algorithm. Experiment with this solution to see if it fits your requirements. Otherwise, consider alternative methods.
If the above method proves successful, you may opt for a simpler signature such as:
type TTest = <A>(src: TInputs<A>) => (x: A) => A
This alternative retains A
while deriving
Src</code from it. This strategy eliminates the need for conditional types but necessitates the compiler to infer <code>A
from a value of type
TInputs<A>. Determine whether this method works effectively for your situation or if adjustments are needed.</p>
<p>Wishing you all the best once again.</p>
</div></answer1>
<exanswer1><div class="answer accepted" i="53861092" l="4.0" c="1545256077" m="1545268546" v="2" a="amNhbHo=" ai="2887218">
<p>The TypeScript compiler will not use a generic constraint as an inference position. See <a href="https://github.com/Microsoft/TypeScript/issues/20963" rel="nofollow noreferrer">this similar GitHub question</a> for discussion about it. That means that while <code>t(arr)
causes
Src</code to be inferred as <code>number[]
, the resulting constraint
number[] extends A[]
cannot be used to infer
A
. And since nothing else can be used to infer
A
, the inference fails with the "I give up" empty type
{}
.
To fix it... you probably don't actually need two type parameters. If you want A
to always be the element type of the Src
array, then you can just get that element type by doing a lookup of Src
's number
-index property type, that is: Src[number]
in place of A
:
type TTest = <Src extends any[]>(src: Src) => (x: Src[number]) => Src[number]
declare const arr: number[]
declare const t: TTest
t(arr) // const t: <number[]>(src: number[]) => (x: number) => number
Looks like it works to me. Hope that helps. Good luck!
UPDATE
Given your new types, one might use conditional type and infer
to get A
from
Src</code, like this:</p>
<pre><code>type AFromSrc<Src extends TInputs<any>> = Src extends TInputs<infer A> ? A : never;
type TTest = <Src extends TInputs<any>>(src: Src) =>
(x: AFromSrc<Src>) => AFromSrc<Src>
This should also work as long as the compiler can infer A
from TInputs<A>
. That depends on TInputs<>
being transparent enough to the inference algorithm. You should check to see if it works for you. If not you might have to be more clever.
But if it does work then you might want to use the following, simpler signature:
type TTest = <A>(src: TInputs<A>) => (x: A) => A
That is, keep A
and compute
Src</code from it. This involves no conditional types but does expect the compiler to be able to infer <code>A
from a value of type
TInputs<A>
. If it can, great. If not, you will need to use the first signature and a custom
AFromSrc
that helps the compiler determine
A
.
Okay, good luck again.