0Pricing
TypeScript Academy · 课时

可变参数函数的类型标注

使用可变参数元组类型构建灵活的 API。

可变参数函数的类型标注 是 CoddyKit 上的免费 TypeScript Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 TypeScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 TypeScript Academy 课程共包含 4 节课。

泛型可变参数函数

可变参数元组类型允许泛型捕获和操作参数列表。这使得用于拼接元组、转发参数以及重塑调用签名的工具能够实现完整的类型安全。

将参数捕获为元组

约束为 unknown[] 的泛型可以将完整的参数列表捕获为元组类型 T,同时保留每个参数的类型和位置。

function tuple<T extends unknown[]>(...args: T): T {
  return args
}
const t = tuple("a", 1, true) // type [string, number, boolean]
console.log(t)

展开泛型元组

您可以将捕获的泛型元组展开到另一个参数列表中。这样可以转发参数,同时保留其精确类型。

function wrap<T extends unknown[]>(fn: (...args: T) => void) {
  return (...args: T) => fn(...args)
}
const log = wrap((n: number, s: string) => console.log(n, s))
log(1, "hi")

拼接两个元组

组合元组时,可变参数元组类型尤其擅长发挥作用。在返回类型中展开两个泛型元组,就会生成它们的拼接结果。

function concat<A extends unknown[], B extends unknown[]>(a: A, b: B): [...A, ...B] {
  return [...a, ...b]
}
const r = concat([1, 2], ["a"]) // [number, number, string]
console.log(r)

结果类型为何如此精确

由于 [...A, ...B] 会展开泛型元组,因此结果会保留每个元素的类型和顺序,而不只是一个类型被拓宽后的联合数组。

function concat<A extends unknown[], B extends unknown[]>(a: A, b: B): [...A, ...B] {
  return [...a, ...b]
}
const r = concat([true], [42])
const flag: boolean = r[0]
const num: number = r[1]
console.log(flag, num)

在前面添加参数

可变参数元组可以让您重塑参数列表,例如为回调函数的签名添加一个开头参数。

function withId<T extends unknown[]>(fn: (...args: T) => void) {
  return (id: number, ...rest: T) => {
    console.log("id", id)
    fn(...rest)
  }
}
const f = withId((msg: string) => console.log(msg))
f(7, "hello")

提取头部类型

对于元组参数,您可以使用带标签的元组拆分出第一个元素类型和其余部分,然后分别操作这两部分。

function head<H, T extends unknown[]>(...args: [H, ...T]): H {
  return args[0]
}
const h = head("first", 2, 3) // type string
console.log(h)

参数工具类型

内置的 Parameters<F> 会将函数的参数列表提取为元组,而它本身也是基于可变参数元组类型构建的。您可以在其他位置复用某个签名的参数。

function greet(name: string, age: number) {}
type GreetArgs = Parameters<typeof greet> // [string, number]
const args: GreetArgs = ["Ada", 36]
console.log(args)

使用参数进行转发

将 Parameters 与剩余展开结合起来,可以构建一个包装器,以完全相同的类型将参数转发给已有函数。

function add(a: number, b: number) { return a + b }
function traced(...args: Parameters<typeof add>): number {
  console.log("calling add", args)
  return add(...args)
}
console.log(traced(2, 3))

构建类似柯里化的签名

可变参数元组支持部分应用工具:现在捕获一部分参数,稍后接收其余参数,并对整个过程进行类型检查。

function partial<A extends unknown[], B extends unknown[], R>(
  fn: (...args: [...A, ...B]) => R,
  ...a: A
) {
  return (...b: B) => fn(...a, ...b)
}
const addThree = (x: number, y: number, z: number) => x + y + z
const add5 = partial(addThree, 5)
console.log(add5(2, 3)) // 10

强大但需谨慎

泛型可变参数元组为您提供了精确且可复用的函数形状工具,例如包装器、转发器和拼接器。它们属于高级功能,因此应在类型精度确实能带来收益时再使用。

function pipe2<A extends unknown[], B, C>(
  f: (...a: A) => B,
  g: (b: B) => C
) {
  return (...a: A) => g(f(...a))
}
const fn = pipe2((n: number) => n * 2, (n) => n + 1)
console.log(fn(5)) // 11

快速检查

测试您对泛型可变参数元组的理解。

回顾

可变参数元组类型允许泛型将参数列表捕获为元组,并在参数位置或返回值位置展开它们。这支持元组拼接([...A, ...B])、参数转发、头部与尾部拆分以及部分应用,同时保留精确的元素类型。Parameters<F> 等内置工具也依赖相同的机制。当精确的函数形状类型值得增加复杂度时,请使用这些工具。

常见问题解答

「可变参数函数的类型标注」课时是免费的吗?

是的 — 「可变参数函数的类型标注」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 TypeScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 TypeScript Academy 课程共包含 4 节课。

「可变参数函数的类型标注」这节课中我会学到什么?

使用可变参数元组类型构建灵活的 API。 你通过在浏览器中直接运行的动手代码来练习 TypeScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 TypeScript Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 TypeScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「可变参数函数的类型标注」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 TypeScript Academy 课中编写并运行代码吗?

能。每节 TypeScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 函数中的剩余参数
  2. 数组与对象中的展开运算
  3. 元组剩余元素
  4. 可变参数函数的类型标注
← 返回 TypeScript Academy