返回泛型类型的数组,取决于TypeScript中的泛型参数数组

dw1jzc5e  于 2023-03-31  发布在  TypeScript
关注(0)|答案(1)|浏览(141)

我正在尝试实现一些我不知道目前在TypeScript中是否可行的东西。
主要目标是创建一个函数,根据其参数(数组),将返回不同类型的函数数组,每个函数返回取决于数组的每个成员。并且,最重要的是,函数类型依赖于一些泛型。
这里我有一个不工作但或多或少接近的代码:

type FirstThing<T> = () => T;
type SecondThing<T,X> = (something: X) => T;

type AllThings<T,X> = FirstThing<T> | SecondThing<T,X>;

type FunctionTypes = "firstThing" | " secondThing";

type FunctionParams = {
    option1: FunctionTypes,
    option2: boolean,
}

function someFunction<T, X>(p: FunctionParams[]): AllThings<T,X>[] {
    return p.map(fp => {
        const auxFn = (fp.option1 == "firstThing" ? () => {
            return "aa" as T;
        } : (smth: X) => {
            return "bb" as T
        });
        if (fp.option1 == "firstThing") {
            return auxFn as FirstThing<T>;
        } else {
            return auxFn as SecondThing<T,X>;
        }    
    });
}

正如您所看到的,这并不真正起作用,因为类型在我调用函数时被解析,并且不依赖于FunctionParams数组,而FunctionParams数组不是一般类型的。
我的主要目标是,例如,如果我必须像这样调用函数:

const [f1,f2] = someFunction<string, number>([{option1: "firstThing"}, {option1: "secondThing"}]);

然后f1f2,将被正确地键入FirstThing<T>SecondThing<T,X>,但f1Tf2T可能是不同的类型(在我目前的代码中,所有函数都将具有相同的泛型)。
提前感谢您的帮助!

djmepvbi

djmepvbi1#

您的函数需要另一个泛型参数来跟踪给定的函数参数:

function someFunction<T, X, P extends FunctionParams[]>(
    p: [...P]
): {
    [K in keyof P]: P[K]["option1"] extends "firstThing"
        ? FirstThing<T>
        : SecondThing<T, X>;
} {

但是,您会注意到,当您尝试使用它时,会发出一个错误:

const [f1, f2] = someFunction<string, number>([
    { option1: "firstThing" },
    { option1: "secondThing" },
]);

这是因为如果你传递一个(或两个)类型参数,* 你必须传递所有的类型参数 *。这将破坏这个函数的强类型,因为我们必须重复自己。没有部分类型推断支持(参见ms/TS#26242),我们必须咖喱函数:

function someFunction<T, X>() {
    return function curried<P extends FunctionParams[]>(
        p: [...P]
    ): {
        [K in keyof P]: P[K]["option1"] extends "firstThing"
            ? FirstThing<T>
            : SecondThing<T, X>;
    } {

(* 巧妙地转换返回类型以消除那里的错误 *)

}) as ReturnType<typeof curried<P>>;

现在成功了

const [f1, f2] = someFunction<string, number>()([
    { option1: "firstThing" },
    { option1: "secondThing" },
]);

f1的类型为FirstThing<string>f2的类型为SecondThing<string, number>
Playground

相关问题