制作相似的函数,但排除最后一个参数。

huangapple go评论60阅读模式
英文:

Make similar function but exclude the last argument

问题

我尝试创建一个类型 B,其定义与类型 A 相同,但省略了最后一个参数。我尝试了以下方法,但它仍然要求传入 2 个参数。

type Callback = (msg: string) => void;

type A = (A: string, B: Callback) => void;
type B = <U extends Exclude<Parameters<A>, Callback>>(...args: U) => void;

const b: B = (...args) => {};

b("some string"); // 预期 2 个参数,但只传入了 1 个。

我该如何正确实现这个目标?

英文:

I'm trying to create a type B which defines same function as type A but omits the last parameter. I've tried the following but it still asks for 2 parameters.

type Callback = (msg: string) =&gt; void;

type A = (A: string, B: Callback) =&gt; void;
type B = &lt;U extends Exclude&lt;Parameters&lt;A&gt;, Callback&gt;&gt;(...args: U) =&gt; void;

const b: B = (...args) =&gt; {};

b(&quot;some string&quot;); // Expected 2 arguments, but got 1.

How can I do this properly?

答案1

得分: 1

以下是翻译好的内容:

您可以使用条件类型推断来排除函数类型的最后一个参数:

type ExcludeLastParam<T extends (...args: any) => any> =
    T extends (...args: [...infer I, any]) => infer R ? (...args: I) => R : never;

这将匹配T(...args: [...I, any]) => R,其中IR是编译器使用infer关键字进行推断的一些部分。请注意,[...I, any]可变元组类型,通过将[...I, any]元组类型(比如 [a: string, b: Callback])进行匹配,编译器将推断I为元组的“初始”部分,不包括最后一个条目(因为任意类型会匹配任何类型)(比如 [a: string])。

让我们来测试一下:

type Callback = (msg: string) => void;
type A = (a: string, b: Callback) => void;

type B = ExcludeLastParam<A>;
// type B = (a: string) => void

还有:

type C = (a: string, b: number, c: boolean, d: Date) => string;
type D = ExcludeLastParam<C>;
// type D = (a: string, b: number, c: boolean) => string

看起来很不错!


请注意,您的版本不起作用,因为虽然Parameters实用程序类型可用于提取参数列表作为元组类型,但Exclude<T, U>实用程序类型不会过滤元组类型;它过滤联合类型。由于Parameters<A>的类型是[a: string, b: Callback],过滤掉Callback不会起任何作用(因为Parameters<A>不是联合类型...或者它是单成员联合,而该成员无法赋值给Callback)。

代码播放链接

英文:

You can use conditional type inference to exclude the last parameter from a function type:

type ExcludeLastParam&lt;T extends (...args: any) =&gt; any&gt; =
    T extends (...args: [...infer I, any]) =&gt; infer R ? (...args: I) =&gt; R : never;

This matches T against (...args: [...I, any]) =&gt; R for some I and R that the compiler infers using the infer keyword. Note that [...I, any] is a variadic tuple type and by matching [...I, any] against a tuple type (like, say, [a: string, b: Callback]), the compiler will infer I to be the "initial" part of the tuple excluding the last entry (since the any type will match anything) (like, say, [a: string]).

Let's test it out:

type Callback = (msg: string) =&gt; void;   
type A = (a: string, b: Callback) =&gt; void;

type B = ExcludeLastParam&lt;A&gt;;
// type B = (a: string) =&gt; void

And

type C = (a: string, b: number, c: boolean, d: Date) =&gt; string;
type D = ExcludeLastParam&lt;C&gt;
// type D = (a: string, b: number, c: boolean) =&gt; string

Looks good!


Note that your version doesn't work because, while the Parameters&lt;T&gt; utility type can be used to extract the parameter list as a tuple type, the Exclude&lt;T, U&gt; utility type does not filter tuple types; instead it filters union types. Since Parameters&lt;A&gt; is of type [a: string, b: Callback], filtering out Callback isn't going to do anything (because Parameters&lt;A&gt; is not a union... or maybe it's a single member union, and that member is not assignable to Callback).

Playground link to code

huangapple
  • 本文由 发表于 2023年4月11日 04:21:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/75980432.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定