news 2026/10/2 8:12:28

type-challenges 第 3312 题精解:不使用内置泛型实现 Parameterslt;Tgt;

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
type-challenges 第 3312 题精解:不使用内置泛型实现 Parameterslt;Tgt;
  • 示例工程

【免费下载链接】type-challenges

Collection of TypeScript type challenges with online judge

项目地址:https://gitcode.com/GitHub_Trending/ty/type-challenges
点击查看免费下载

本文聚焦 type-challenges 仓库中的 Easy 级题目Parameters(questions/03312-easy-parameters)。该题要求你在不使用 TypeScript 内置Parameters<T>的前提下,用条件类型与infer关键字手写出等价的MyParameters<T>,用于提取任意函数的参数类型元组。读完本文,你将彻底掌握infer在函数类型匹配中的用法、元组(tuple)类型的构建方式,以及内置Parameters<T>的底层实现原理,并能将同样的推断技巧迁移到ReturnType、ConstructorParameters等更多场景。

题目速览:实现内置 Parameters<T>

题目原文(韩文版 README.ko.md,与英文版 README.md 一致)要求如下:

내장 제네릭Parameters<T>를 이를 사용하지 않고 구현하세요.(不使用内置泛型Parameters<T>,自行实现它。)

题目给出的示例:

const foo = (arg1: string, arg2: number): void => {} type FunctionParamsType = MyParameters<typeof foo> // [arg1: string, arg2: number]

也就是说,MyParameters<typeof foo>应当得到一个元组类型[string, number],它恰好对应foo的两个参数的类型。注意 TypeScript 元组可以携带具名标签(如[arg1: string, arg2: number]),题目注释里展示的正是带标签的形式,但等价的普通元组[string, number]同样满足要求。

这道题在仓库中被标注为easy难度,并带有#infer、#tuple、#built-in三个标签:infer是本题的核心解题工具,tuple是输出结果的类型形态,built-in表示目标是对内置工具类型的复刻。

从模板文件出发:理解类型约束

每个挑战在仓库中都配有模板文件,本题的模板是 template.ts:

type MyParameters<T extends (...args: any[]) => any> = any

模板已经给出了类型参数T的约束条件:T extends (...args: any[]) => any。这意味着:

  • T必须是一个函数类型;
  • 该函数可以接收任意个、任意类型的参数(...args: any[]);
  • 返回值类型不限(=> any)。

这个约束保证了后续对T做模式匹配时不会遇到非函数类型。模板中的= any是待填空的占位符,需要替换为真正的实现。在 JavaScript 运行时层面上,typeof foo拿到的是函数本身;而在类型层面上,typeof foo得到的是它的函数类型(arg1: string, arg2: number) => void——这正是我们要做类型提取的对象。

核心解法:条件类型 + infer

TypeScript 的条件类型(conditional type)允许我们以T extends X ? Y : Z的形式对类型做模式匹配。当X中出现infer关键字时,TypeScript 会尝试推断出对应位置的类型,并在真分支中将其作为新类型变量使用。

据此,标准解法如下:

type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never

逐段拆解:

  1. T extends (...args: infer P) => any:把传入的函数类型T与"具有任意参数列表的函数"这一模式做匹配,infer P让 TypeScript 推断出整个参数列表的类型;
  2. 由于模板约束保证了T一定是函数类型,匹配必然成功,直接走真分支返回P;
  3. P被推断为参数元组,例如对(arg1: string, arg2: number) => void会得到[string, number];
  4. 假分支返回never仅是防御性写法,实际因约束的存在不会触发。

这正是 TypeScript 内置Parameters<T>的官方实现:

type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;

由此可见,本题的"标准答案"与 TypeScript 内置工具类型的源码几乎一字不差——infer P推断出的P天然就是一个元组类型,不需要任何额外的拼接或转换。这就是该题目同时打上#infer与#tuple两个标签的原因:答案本身就是一个 infer 推断出的元组。

用仓库测试用例验证:Equal 与 Expect

仓库为每个题目都提供了在线判题的测试文件。本题的 test-cases.ts 定义了三个函数与三组断言:

import type { Equal, Expect } from '@type-challenges/utils' function foo(arg1: string, arg2: number): void {} function bar(arg1: boolean, arg2: { a: 'A' }): void {} function baz(): void {} type cases = [ Expect<Equal<MyParameters<typeof foo>, [string, number]>>, Expect<Equal<MyParameters<typeof bar>, [boolean, { a: 'A' }]>>, Expect<Equal<MyParameters<typeof baz>, []>>, ]

测试覆盖了三种典型场景:

被测函数期望结果覆盖要点
foo(arg1: string, arg2: number): void[string, number]多参数、基础类型
bar(arg1: boolean, arg2: { a: 'A' }): void[boolean, { a: 'A' }]含对象字面量类型的参数
baz(): void[]零参数函数应得到空元组

其中Equal与Expect来自仓库自带的类型工具 utils/index.d.ts:

export type Expect<T extends true> = T export type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false

Expect<T>要求T必须是字面量true,否则编译报错;Equal<X, Y>通过函数类型协变比较实现了对两个类型完全相等的严格判定(比extends的双向可赋值更严格,能区分any、never等微妙情形)。测试用例说明:

  • MyParameters<typeof foo>必须精确等于[string, number],而不是any、unknown[]或超集类型;
  • 零参数函数baz的参数列表推断为空元组[],证明infer P对空参数同样成立。

在本地验证时,可将 template.ts 中的占位符替换为T extends (...args: infer P) => any ? P : never,再配合 test-cases.ts 运行 TypeScript 编译检查(仓库根目录的 package.json 声明了typescript依赖),若全部断言通过则解答正确。

边界情况与注意事项

  • 零参数函数:baz(): void会被推断为[],这符合Parameters的行为——返回空元组而非never;
  • 带默认值或可选参数:(a?: string, b = 1) => void会推断为[a?: string, b?: number](可选参数对应可选元组元素),推断逻辑由 TypeScript 的类型推断规则直接给出;
  • 带标签元组:若使用具名参数,推断结果可能保留参数名(如[arg1: string, arg2: number]),这与题目注释展示的形式一致;
  • 泛型函数:对function id<T>(x: T): T,Parameters<typeof id>推断为[x: unknown],因为typeof拿到的是泛型函数的具体化类型;
  • 约束之外的类型:模板约束T extends (...args: any[]) => any使MyParameters<number>这类调用直接报类型错误,保证了解答的安全性。

延伸:infer 在工具类型中的复用

掌握本题后,infer的其他应用几乎是同一思路的变体,这也解释了为什么本题被归类为 easy。仓库中同属 infer 主题的进阶题目还有:

  • 00002-medium-return-type:用T extends (...args: any[]) => infer R ? R : any提取返回值类型;
  • 00003-medium-omit:用keyof T与映射类型实现对象键的剔除;
  • 00062-medium-type-lookup:在联合类型上用T extends { type: infer U }做按字段匹配的查找。

它们的共同模式可以概括为:先用条件类型约束目标形态,再用infer在指定位置提取类型,最后在真分支中组织输出。你还可以把infer用在数组元素提取(T extends [infer F, ...infer R])、字符串模板匹配(T extends \${infer A}-${infer B}`)等场景,这些技巧在仓库 [guides](https://link.gitcode.com/i/047f64a4c7dc4f3a1e583196f478bbbf) 目录的进阶指南中均有涉及。可以说,把Parameters ` 这道题吃透,就等于打开了 TypeScript 类型编程的大门。

小结

第 3312 题 Parameters 的核心收获有三点:其一,typeof运算符可以把运行时函数值转换为类型层面的函数类型;其二,条件类型配合infer能够从函数类型中精确提取参数列表,且结果天然是元组;其三,一行实现T extends (...args: infer P) => any ? P : never恰好就是内置Parameters<T>的官方源码,体现了"复刻内置工具类型"这类题目(#built-in)的典型解题路径。对照仓库中的 template.ts 与 test-cases.ts 完成填空并通过测试,你就完成了本次挑战。

  • 示例工程

【免费下载链接】type-challenges

Collection of TypeScript type challenges with online judge

项目地址:https://gitcode.com/GitHub_Trending/ty/type-challenges
点击查看免费下载
上一篇:d2s-editor:暗黑破坏神2存档编辑器的终极开源解决方案
下一篇:终极解决方案:智能管理Visual C++运行库,彻底告别dll缺失烦恼

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 8:12:13

C/C++内存管理+模板初阶

目录 一. C/C内存分布 二. C语言中动态内存管理方式 三. C内存管理方式 3.1 new/delete 操作内置类型 3.2 new/delete 操作自定义类型 四. operator new与operator delete函数 五. new和delete的实现原理 5.1 内置类型 5.2 自定义类型 六. 定位new表达式(placement-n…

作者头像 李华
网站建设 2026/10/2 8:09:49

Agent循环的隐形代价:Strands Harness SDK如何把生产级封装成一行代码

做 AI 应用这些年&#xff0c;我越来越确认一个反直觉的结论&#xff1a;Agent 项目里最贵的东西不是模型 token&#xff0c;而是那套没多少人爱写、又不得不写的 Agent 循环。过去大半年&#xff0c;我前后手写过五个循环&#xff0c;每一个都从“无非是个 while 加几次模型调…

作者头像 李华
网站建设 2026/10/2 8:09:05

GNU Radio定时环路实战:精准锁定P201Pro采样时刻

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 8:08:05

从零构建AI工程:超越模型训练的系统化实践

1. 为什么“从零构建AI工程”不是写个模型就完事了“AI Engineering from Scratch”这个标题&#xff0c;乍看像极了某本技术书的副标题&#xff0c;或者某个开源项目的README第一行。但如果你真照着字面意思去干——下载PyTorch、抄一段ResNet代码、跑通MNIST&#xff0c;然后…

作者头像 李华