'Typescript: Evaluate type of generic function

Is there any trick to "evaluate" the type of a generic fuction?

Consider the following:

type Arr = <A>() => A[]

type Ev<G, A> = ???

Question: Is it possible to fill in ??? such that Ev<Arr, A> equals () => A[]? (As compared to <A>() => A[])


(Update 2022/04/26)

Something similar/related will be possible with TS 4.7; Even though that's not fully what we'd want here.

https://github.com/microsoft/TypeScript/pull/47607


Some more examples for the desired behavior:

Ev<<A>() => A[], number>
    // should evaluate to
    // () => number[]

Ev<<A>() => string, number>
    // should evaluate to
    // () => string

Ev<<A>() => [string, A], { some: "thing" }>
    // should evaluate to
    // () => [string, { some: "thing" }]

A simplified version of the question would be: Can we define

type EvNum<A> = ???

such that

EvNum<
   <X>() => X
> // should be `number`

EvNum<
   <X>() => X[]
> // should be `number[]`

EvNum<
   <X>() => [X, "hi"]
> // should be `[number, "hi"]`

EvNum<
   <X>() => SomeGenericType<X>
> // should be `SomeGenericType<number>`

EvNum<
   <X>() => "constant"
> // should be `"constant"`


Solution 1:[1]

As to your first question, those are referred to as Higher Kinded Types, and are not supported in Typescript as of this answer.

A Higher Kinded Type is simply "A type that abstracts over some type that, in turn, abstracts over another type." So if you want a type, that you pass in a type to abstractly create a new type, that is an example of a higher kinded type. And it is not possible in TS.

You cannot pass a second type into a generic type and come out with a derived type.

Your last example (simplified) is literally ReturnType so not sure what you are meaning. It is perfectly possible to come up with. But you can't make a type that comes up with it.

type EvNum<T> = () => T;
type Arr<T> = T[];

function func<T>(param: EvNum<T>): T {
    return param();
}

let x1 = func(()=> 4); //number
let x2 = func(()=> [4]); //number[]
let x3 = func(()=> [4, "hi"] as const); //[4, "hi"]
let x4 = func(()=> "constant" as const); //"constant"
let cool: Arr<number> = [4, 5, 6];
let x5 = func(() => cool); //Arr<number>

This passes your requested types

Solution 2:[2]

If I understand you correctly it should be:

type EV<T> = () => T;

Otherwise the question makes no sense or must be explained in more detail.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tim
Solution 2 Jan Bürling