gpt4 book ai didi

typescript - 推断重载函数的参数

转载 作者:行者123 更新时间:2023-12-05 01:49:21 28 4
gpt4 key购买 nike

是否可以推断重载函数的参数?

例如:

type MyFunction = {
(key: "one", params: { first: string }): void;
(key: "two", params: { second: string }): void;
}

type MyFunctionParams<T extends string> = MyFunction extends (
key: T,
params: infer P,
) => void
? P
: never;

// should be `{ first: string }`
type OneParams = MyFunctionParams<"one"> // never

Typescript playground

最佳答案

如果您控制MyFunction 的定义,我会遵循caTS's excellent approach从另一个角度来看它。 (有时令人惊讶的是,如果您改变起点,就可以简化某些事情,甚至可以使原本不可能的事情成为可能,而且通常不会产生负面后果。)

但是,如果您必须使用现有的 MyFunction 类型,那么: 两种可能的解决方案,一种是通用的,另一种是更实用的有针对性的,坦率地说,这两种解决方案都不如我们可能希望的那样令人满意喜欢:

通用解决方案

遗憾的是,访问函数重载类型的参数信息(或返回类型信息)非常困难和冗长——但有可能。如 this question's answers 中所述,这只是 ParametersReturnType 的限制,它们无法按照我们想要的方式处理重载。你的问题就是一个很好的例子。这是一个更简单的 ( playground ):

type MyFunction = {
(key: "one", params: { first: string }): void;
(key: "two", params: { second: string }): void;
};

type MyFunctionKey = Parameters<MyFunction>[0];
// ^? type MyFunctionKey = "two"
// Huh?!? I think most of us would expect `"one" | "two"`, but
// that's just not the way it is. (There's usually a good reason
// for these limitations in the general case, but...)

但它可能的在合理范围内,在这种情况下,“合理”是函数可能重载的合理最大数量。让我们将 6 作为我们的最大过载限制。

Titian's answer to that question可以看出,可以知道一个函数有多少重载,并推断出它们的参数列表。例如:

type Whatever<F> =
F extends {
(...args: infer Params1): any);
(...args: infer Params2): any);
}
? // This branch is used if F has **exactly** two overloads
: // Otherwise this one is
;

我们可以使用该机制来处理 2、3、4、5...直到您想要可能的重载集的任何合理限制。所以这是我们难题的第一部分,MyFunctonParams 根据参数帮助器类型有多少重载进行分派(dispatch):

type MyFunctionParams<KeyType> =
MyFunction extends {
(...args: infer P1): any;
(...args: infer P2): any;
}
? ParamsHelper<KeyType, P1, P2>
: MyFunction extends {
(...args: infer P1): any;
(...args: infer P2): any;
(...args: infer P3): any;
}
? ParamsHelper<KeyType, P1, P2, P3>
: MyFunction extends {
(...args: infer P1): any;
(...args: infer P2): any;
(...args: infer P3): any;
(...args: infer P4): any;
}
? ParamsHelper<KeyType, P1, P2, P3, P4>
: MyFunction extends {
(...args: infer P1): any;
(...args: infer P2): any;
(...args: infer P3): any;
(...args: infer P4): any;
(...args: infer P5): any;
}
? ParamsHelper<KeyType, P1, P2, P3, P4, P5>
: MyFunction extends {
(...args: infer P1): any;
(...args: infer P2): any;
(...args: infer P3): any;
(...args: infer P4): any;
(...args: infer P5): any;
(...args: infer P6): any;
}
? ParamsHelper<KeyType, P1, P2, P3, P4, P5, P6>
: never;

ParamsHelper 的工作是将我们提供的 KeyType 与我们传递给它的每个参数元组的第一个元素(您的 key)相匹配并提供第二个元素的类型(您的 params):

type ParamsHelper<
KeyType,
P1 extends any[],
P2 extends any[] = [never, never],
P3 extends any[] = [never, never],
P4 extends any[] = [never, never],
P5 extends any[] = [never, never],
P6 extends any[] = [never, never]
> = KeyType extends P1[0]
? P1[1]
: KeyType extends P2[0]
? P2[1]
: KeyType extends P3[0]
? P3[1]
: KeyType extends P4[0]
? P4[1]
: KeyType extends P5[0]
? P5[1]
: KeyType extends P6[0]
? P6[1]
: never;

就是这样!现在我们得到了想要的结果,前提是 MyFunction 没有超过六个重载(或您决定设置的任何限制):

type OneParams = MyFunctionParams<"one">;
// ^? type OneParams = { first: string; }

type TwoParams = MyFunctionParams<"two">;
// ^? type TwoParams = { second: string; }

Playground example

在该示例中,MyFunctionParams 绑定(bind)到 MyFunction,但如果我们希望将函数类型传递到其中,我们可以制作一个通用版本。对于你的例子来说似乎有点矫枉过正,但是 here that is .

务实的目标解决方案

如果我们只是想处理MyFunction,我们可能会采取更简洁和更有针对性的方法,像这样:

type MyFunction1 = {
(key: "one", params: { first: string }): void;
};
type MyFunction2 = {
(key: "two", params: { second: string }): void;
};
type MyFunction = MyFunction1 & MyFunction2;

type MyFunctionParams<KeyType> =
KeyType extends Parameters<MyFunction1>[0]
? Parameters<MyFunction1>[1]
: KeyType extends Parameters<MyFunction2>[0]
? Parameters<MyFunction2>[1]
: never;

type OneParams = MyFunctionParams<"one">;
// ^? type OneParams = { first: string; }

type TwoParams = MyFunctionParams<"two">;
// ^? type TwoParams = { second: string; }

Playground link

不太令人满意,当然每次你添加另一个重载时,你都必须编辑 MyFunctionParams 类型来处理它,但有时更简单和有针对性的更好,这取决于你的情况.

关于typescript - 推断重载函数的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74208041/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com