【发布时间】:2021-05-04 13:34:10
【问题描述】:
(TypeScript Playground 中的完整代码:link。)
我有一个 Result<T, E> 类型,用于计算成功并返回 T 类型的值或失败并返回 E 类型的错误。
type Result<T, E> =
| {ok: true, value: T}
| {ok: false, value: E};
我想编写一个辅助函数,它可以按顺序运行Result-returning 函数的列表。如果任何函数失败,则停止处理并返回错误。如果全部成功,则返回成功值列表。
以下是专门为长度为 3 的列表实现该功能的方法:
function sequenceFixed<T1, T2, T3, E>(fns: [() => Result<T1, E>, () => Result<T2, E>, () => Result<T3, E>]): Result<[T1, T2, T3], E> {
const [f1, f2, f3] = fns;
const r1 = f1();
if (!r1.ok) return r1;
const r2 = f2();
if (!r2.ok) return r2;
const r3 = f3();
if (!r3.ok) return r3;
return {ok: true, value: [r1.value, r2.value, r3.value]};
}
我想使用 TypeScript 4.0 的可变元组类型来使它适用于任何长度的列表。 (函数体本身不需要类型检查,只需要调用站点。)
这是我的两次尝试:
declare function sequenceGeneric1<T extends Array<unknown>, E>(
fns: Readonly<{[P in keyof T]: () => Result<T[P], E>}>,
): Result<[...T], E>;
declare function sequenceGeneric2<Fns extends Array<unknown>, E>(
fns: Fns,
): Result<{[P in keyof Fns]: ExtractResultSuccessType<Fns[P]>}, E>;
type ExtractResultSuccessType<Fn> = Fn extends () => Result<infer T, unknown> ? T : unknown;
如果我明确传递类型参数,则正确调用这些函数类型检查,但我不知道如何让 TypeScript 推断类型参数。
declare function f1(): Result<string, string>;
declare function f2(): Result<boolean, string>;
declare function f3(): Result<number, string>;
function checkFixed() {
return sequenceFixed([f1, f2, f3]);
}
function checkGeneric1() {
return sequenceGeneric1([f1, f2, f3]);
}
function checkGeneric2() {
return sequenceGeneric2([f1, f2, f3]);
}
function check() {
// ok
const c1: Result<[string, boolean, number], string> = checkFixed();
// ERROR: Type 'Result<(string | number | boolean)[], unknown>' is not assignable to
// type 'Result<[string, boolean, number], string>'.
const c2: Result<[string, boolean, number], string> = checkGeneric1();
// ERROR: Type 'Result<(string | number | boolean)[], unknown>' is not assignable to
// type 'Result<[string, boolean, number], string>'.
const c3: Result<[string, boolean, number], string> = checkGeneric2();
}
function checkGeneric1WithAnnontation(): Result<[string, boolean, number], string> {
return sequenceGeneric1<[string, boolean, number], string>([f1, f2, f3]);
}
【问题讨论】:
-
感谢在 Playground 链接中提供minimal reproducible example;它使工作变得更加容易。
标签: typescript typescript-generics variadic-tuple-types