【发布时间】:2022-01-17 16:55:26
【问题描述】:
TS 4.0 允许传播元组类型和标记元组类型。
我正在尝试使用这两个功能来创建一种带有上下文的函数或括号模式。
这是我的尝试:
type Resource<T = void> = () => Promise<[
release: () => Promise<void>,
resource: T
]>;
async function withF<
Resources extends Array<Resource<unknown>>,
Result
>(
resources: Resources,
f: (...resources: [...Resources]) => Promise<Result>
): Promise<Result> {
const releases = [];
const items = [];
try {
for (const resource of resources) {
const [release, item] = await resource();
releases.push(release);
items.push(item);
}
return await f(...items);
} finally {
releases.reverse();
for (const release of releases) {
await release();
}
}
}
这个想法是你可以像这样使用它:
let count: number = 0;
await withF(
[
async () => {
++count;
return [async () => { --count; }, count];
}
],
async (c: number) => {
return c;
}
);
问题是类型不匹配,因为在我的:
f: (...resources: [...Resources]) => Promise<Result>
Resources 扩展了Array<Resource<unknown>>,我想说f 对Resources 的每个返回类型承诺的第二个元素进行扩展。
第一个挑战是如何将映射类型映射到Resources。 https://devblogs.microsoft.com/typescript/announcing-typescript-3-1/#mappable-tuple-and-array-types 似乎应该可以。
第二步是应用索引选项。这也应该适用于映射类型。但是我又不知道该怎么做。
理想情况下,我们需要某种类型的构造函数:
f: (...resources: [...TC<Resources>]) => Promise<Result>
其中TC 是一个特殊的类型构造函数,它将Resources 映射到每个返回类型的第二个元素,并且仍然保留元组长度和顺序。
进一步尝试映射到函数元组:
type Functions = ((...args: any) => unknown)[];
type FunctionReturns<T extends [...Functions]> = { [K in keyof T]: ReturnType<T[K]> };
const fs: Functions = [() => 1, () => 'abc'];
type FsReturns = FunctionReturns<typeof fs>;
无论出于何种原因,即使映射到元组类型的基本能力有效,这里的ReturnType 仍然抱怨,即使我们已经说过T 扩展了一个函数数组。尝试映射到元组类型时,ReturnType 似乎不起作用。
【问题讨论】: