如何将 Array#map 结果分配给可变元组`[P in keyof T]: ReturnType<T[P]>`?
How to assign Array#map results to variadic tuple `[P in keyof T]: ReturnType<T[P]>`?
我正在尝试创建一个强类型函数,该函数映射到 return 任意值的同类函数数组。
我对这两种方法都进行了试验,虽然它们都成功地 return 了正确的类型,但我在 return 值中遇到了错误:
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]
匹配return类型的正确方法是什么?
执行此操作的最简单(也许唯一)方法是从 unknown[]
return 由 .map
显式转换为 return 的复杂类型 runAll
。我知道这感觉不对,但你知道转换总是安全的,所以在函数内部进行转换并不可怕。我离开了你的第二个例子,还修复了我从 return 类型得到的次要错误。 (我可能有较新的 TS 版本。) 结果:
type AllResults<T> = {
[P in keyof T]: T[P] extends (() => unknown) ? ReturnType<T[P]> : never;
};
const runAll = <T extends Array<() => unknown>>(
actions: [...T],
): AllResults<T> => actions.map(action => action()) as AllResults<T>;
const results = runAll([
() => 'hello',
() => 123,
() => true,
]);
// const results: [string, number, boolean]
C考虑下一个例子:
type Fn = () => any
type MapPredicate<F> = F extends Fn ? ReturnType<F> : never
/**
* Iterate through [array] argument and get return type
*/
type Mapped<
Arr extends Array<unknown>,
Result extends Array<unknown> = []
> = Arr extends []
? []
: Arr extends [infer H]
? [...Result, MapPredicate<H>]
: Arr extends [infer Head, ...infer Tail]
? Mapped<[...Tail], [...Result, MapPredicate<Head>]>
: Readonly<Result>;
/**
* Overload
* see docs https://www.typescriptlang.org/docs/handbook/functions.html#overloads
*/
function runAll<Cb extends Fn, Cbs extends Cb[]>(
array: [...Cbs],
): Mapped<Cbs>
function runAll<Cb extends Fn, Cbs extends Cb[]>(
array: [...Cbs],
) {
return array.reduce<ReadonlyArray<ReturnType<Cbs[number]>>>(
(acc, elem) => [...acc, elem()],
[]
)
}
const results = runAll([
() => 'hello',
() => 123,
() => true,
]); // [string, number, boolean]
显式 return type
通常不适用于遍历数组的函数。这里最好使用重载
我添加了 Mapped
助手。 IT 只是递归地遍历 array
参数类型和 returns return 回调类型。
类似于array.map(elem=>elem())
Here,在我的博客中,你可以找到更多有趣的例子
我正在尝试创建一个强类型函数,该函数映射到 return 任意值的同类函数数组。
我对这两种方法都进行了试验,虽然它们都成功地 return 了正确的类型,但我在 return 值中遇到了错误:
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]
匹配return类型的正确方法是什么?
执行此操作的最简单(也许唯一)方法是从 unknown[]
return 由 .map
显式转换为 return 的复杂类型 runAll
。我知道这感觉不对,但你知道转换总是安全的,所以在函数内部进行转换并不可怕。我离开了你的第二个例子,还修复了我从 return 类型得到的次要错误。 (我可能有较新的 TS 版本。) 结果:
type AllResults<T> = {
[P in keyof T]: T[P] extends (() => unknown) ? ReturnType<T[P]> : never;
};
const runAll = <T extends Array<() => unknown>>(
actions: [...T],
): AllResults<T> => actions.map(action => action()) as AllResults<T>;
const results = runAll([
() => 'hello',
() => 123,
() => true,
]);
// const results: [string, number, boolean]
C考虑下一个例子:
type Fn = () => any
type MapPredicate<F> = F extends Fn ? ReturnType<F> : never
/**
* Iterate through [array] argument and get return type
*/
type Mapped<
Arr extends Array<unknown>,
Result extends Array<unknown> = []
> = Arr extends []
? []
: Arr extends [infer H]
? [...Result, MapPredicate<H>]
: Arr extends [infer Head, ...infer Tail]
? Mapped<[...Tail], [...Result, MapPredicate<Head>]>
: Readonly<Result>;
/**
* Overload
* see docs https://www.typescriptlang.org/docs/handbook/functions.html#overloads
*/
function runAll<Cb extends Fn, Cbs extends Cb[]>(
array: [...Cbs],
): Mapped<Cbs>
function runAll<Cb extends Fn, Cbs extends Cb[]>(
array: [...Cbs],
) {
return array.reduce<ReadonlyArray<ReturnType<Cbs[number]>>>(
(acc, elem) => [...acc, elem()],
[]
)
}
const results = runAll([
() => 'hello',
() => 123,
() => true,
]); // [string, number, boolean]
显式 return type
通常不适用于遍历数组的函数。这里最好使用重载
我添加了 Mapped
助手。 IT 只是递归地遍历 array
参数类型和 returns return 回调类型。
类似于array.map(elem=>elem())
Here,在我的博客中,你可以找到更多有趣的例子