Skip to content

追加参数

约 465 字大约 2 分钟

2022-12-01

题目

Github: Append Argument

实现一个泛型 AppendArgument<Fn, A>,对于给定的函数类型 Fn,以及一个任意类型 A,返回一个新的函数 GG 拥有 Fn 的所有参数并在末尾追加类型为 A 的参数。

type Fn = (a: number, b: string) => number

type Result = AppendArgument<Fn, boolean>
// 期望是 (a: number, b: string, x: boolean) => number

解题思路

首先我们可以使用 infer 关键字来推断出函数的参数类型和返回值类型。通过条件类型的类型推断来实现这一点。

type AppendArgument<Fn, A> = Fn extends (args: infer P) => infer R
  ? (args: P) => R
  : never

但需要注意的是,这里的 (args:infer P) 只能获取首个参数的类型,因此我们需要使用 ... 展开语法来获取所有参数的类型。

type AppendArgument<Fn, A> = Fn extends (...args: infer P) => infer R
  ? (...args: P) => R
  : never

此时获取的类型参数 P 为一个可变元组类型,可以使用 ... 展开语法来获取参数的类型,并添加 A 类型的参数。 构造新的函数参数签名。

答案

type AppendArgument<Fn extends (...args: any[]) => any, A> =
  Fn extends (...args: infer P) => infer R ? (...args: [...P, A]) => R : never

验证

type 
Case1
=
AppendArgument
<(
a
: number,
b
: string) => number, boolean>
type
Result1
= (
a
: number,
b
: string,
x
: boolean) => number
type
Case2
=
AppendArgument
<() => void, undefined>
type
Result2
= (
x
: undefined) => void
type
cases
= [
Expect
<
Equal
<
Case1
,
Result1
>>,
Expect
<
Equal
<
Case2
,
Result2
>>,
// @ts-expect-error
AppendArgument
<unknown, undefined>,
]

参考