追加参数
题目
Github: Append Argument
实现一个泛型 AppendArgument<Fn, A>
,对于给定的函数类型 Fn
,以及一个任意类型 A
,返回一个新的函数 G
。 G
拥有 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
验证
import type { Expect, Equal } from '~/tc-utils'
type AppendArgument<Fn extends (...args: any[]) => any, A> =
Fn extends (...args: infer P) => infer R ? (...args: [...P, A]) => R : never
// ---cut---
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>,
]