I have doubts about the accuracy of typing this correctly. It seems like you are dealing with a tuple rather than an array, as the functions in question have different signatures and the return type of arrayElementTypes
should match each function's return type in the tuple.
However, I don't want to rule out the possibility completely, as I've seen some remarkable solutions achieved through the use of generics and conditional types before.
Edit: I have devised some foundational types that could assist in finding the solution, but it will require some assembly on your end :)
// defining any function
type Fn = () => unknown;
// representing a tuple/array of functions
type FnArr = readonly Fn[];
// extracting the first function in the tuple
type Head<T extends FnArr> = T extends [infer HeadFn, ...any[]] ? HeadFn : never;
// obtaining the remaining functions in the tuple
type Tail<T extends FnArr> = T extends [any, ...infer TailFns] ? TailFns : never;
Using these basic building blocks, you can derive the return types of each function within your tuple. While this doesn't offer a direct solution, leveraging recursively defined conditional types could potentially lead you to one :)
const [varA, varB, varC] = arrayElementTypes( () => "", () => ({prop: "prop"}), () => [1,2,3] )
// how can this be typed appropriately so that the :
// varA: string
// varB: {prop: string}
// varC: number[]
type ExampleFns = [ () => string, () => {prop: "prop"}, () => number[] ];
type TypeForVarA = ReturnType<Head<ExampleFns>>; // F1 = string
type TypeForVarB = ReturnType<Head<Tail<ExampleFns>>>; // F2 = {prop: "prop"}
type TypeForVarC = ReturnType<Head<Tail<Tail<ExampleFns>>>>; // F3 = number[]