I'm trying to create a strongly-typed function that maps over a homogeneous array of functions that return an arbitrary value.
I've experimented with both of these, and while they both successfully return the correct types, I get errors in the return value:
const runAll = <T extends (() => any)[]>(
array: [...T],
): {
[P in keyof T]: ReturnType<T[P]>
} => {
const result = [];
for (let i = 0; i < array.length; i += 1) {
result.push(array[i]());
}
return result;
}
// ^ Error: Type 'any[]' is not assignable to type '{ [P in keyof T]: ReturnType<T[P]>; }'.ts(2322)
const results = runAll([
() => 'hello',
() => 123,
() => true,
]);
// const results: [string, number, boolean]
const runAll = <T extends (() => unknown)[]>(
actions: [...T],
): {
[P in keyof T]: ReturnType<T[P]>;
} => actions.map(action => action());
// ^ Error: Type 'unknown[]' is not assignable to type '{ [P in keyof T]: ReturnType<T[P]>; }'.ts(2322)
const results = runAll([
() => 'hello',
() => 123,
() => true,
]);
// const results: [string, number, boolean]
What is the correct way to match the return type?
The simplest (and perhaps only) way to do this is to explicitly cast from the
unknown[]
returned by.map
to the complex return type ofrunAll
. I know that feels wrong, but you know that the cast will always be safe, so it's not terrible to make it internally within the function. I went off your second example, and also fixed a secondary error I got from the return type. (I probably have a newer TS version.) The result: