)
示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载本篇文章深入解析 type-challenges 仓库中的00270-hard-typed-get挑战题目原文如何用 TypeScript 4.1 引入的模板字面量类型Template Literal Types为 lodash 风格的get函数编写出保留完整类型信息的类型定义。读完本文你将掌握infer拆分字符串、点路径逐段递归下钻的完整实现方案并理解题目测试用例中埋藏的两个关键边界条件。挑战背景为什么 lodash 的 get 会丢失类型信息lodash 的get是一个在 JavaScript 中访问嵌套值非常方便的工具函数可以传入形如foo.bar.count的路径字符串安全地取出深层对象里的值。然而在 TypeScript 中直接使用这类函数会丢失类型信息get(data, foo.bar.count)的返回值通常只会被推断为any或联合类型调用方无法在编译期得知路径是否真实存在、取到的值究竟是什么类型。随着 TypeScript 4.1 引入模板字面量类型我们终于可以把foo.bar.count这样的字符串在类型层面拆解成一段段键名从而为get写出真正类型安全的版本。这道 hard 难度的挑战元数据见 info.yml标签为utils与template-literal作者为 Anthony Fu就是要求你实现这样一个类型工具type GetT, K /* 你的实现 */ string仓库中的 template.ts 给出的起点就是一个占位实现type GetT, K string它永远返回string需要你替换为真正的逻辑。题目要求与示例题目给出的目标类型Data和期望输出如下取自 README.mdtype Data { foo: { bar: { value: foobar, count: 6, }, included: true, }, hello: world } type A GetData, hello // world type B GetData, foo.bar.count // 6 type C GetData, foo.bar // { value: foobar, count: 6 }可以看到核心要求是K为单层键时直接取该键对应的值类型K为带点的路径时沿着路径逐层深入最终返回最深层值的类型。题目同时明确说明本挑战不要求支持数组索引访问即不需要处理foo.0.bar这类路径。测试用例里隐藏的两个边界条件只看 README 的示例容易低估这道题的难度。实际判定正确性的测试用例在 test-cases.ts它比 README 多出了两条关键的用例import type { Equal, Expect } from type-challenges/utils type cases [ ExpectEqualGetData, hello, world, ExpectEqualGetData, foo.bar.count, 6, ExpectEqualGetData, foo.bar, { value: foobar, count: 6 }, ExpectEqualGetData, foo.baz, false, ExpectEqualGetData, no.existed, never, ] type Data { foo: { bar: { value: foobar count: 6 } included: true } foo.baz: false hello: world }注意与 README 示例不同这里的Data额外增加了一个字面量键foo.baz且其值为false。由此产生两个必须满足的边界条件字面量键优先于路径解析GetData, foo.baz的结果必须是false而不是never。虽然foo.baz看起来像一条通往foo.baz属性的路径而foo下并没有baz字段但 TypeScript 的keyof能识别出foo.baz是Data的一个真实键名因此应直接命中T[K]。不存在的路径返回neverGetData, no.existed必须得到never表示查无此属性而不是报类型错误或返回any。解题思路从拆分路径到递归下钻正确实现的关键可以拆成三个步骤第一步先查字面量键。用条件类型判断K extends keyof T如果成立直接返回T[K]。这同时覆盖了两类情况单层键hello以及本身就是键名的点号字符串foo.baz。第二步拆分路径。当K不是T的键时利用模板字面量类型的模式匹配把它拆成第一段键名 剩余路径K extends ${infer Head}.${infer Rest}infer Head会捕获第一个.之前的部分infer Rest捕获剩余部分。例如foo.bar.count会被拆成Head foo、Rest bar.count。第三步递归下钻。先确认Head extends keyof T第一段键真实存在于当前对象中然后递归调用自身GetT[Head], Rest把问题缩小为在更内层的对象里继续解析剩余路径。若第一段键不存在或路径中不含.却也不是合法键则返回never。一个符合上述逻辑的完整实现如下type GetT, K K extends keyof T ? T[K] : K extends ${infer Head}.${infer Rest} ? Head extends keyof T ? GetT[Head], Rest : never : never逐用例验证GetData, hellohello extends keyof Data成立返回world。GetData, foo.bar.count不是直接键拆分为foobar.countfoo是键递归GetData[foo], bar.count→ 再拆分barcount→ 递归Get{value,count}, count→count是键返回字面量类型6。GetData, foo.bar递归到第二层后bar是foo的子键返回{ value: foobar, count: 6 }。GetData, foo.bazfoo.baz extends keyof Data直接成立它是字面量键返回false。GetData, no.existed不是键拆分noexistedno extends keyof Data不成立返回never。底层原理模板字面量类型 infer 递归这个实现背后是三个 TypeScript 类型能力的组合理解它们也就掌握了这类字符串解析题的通法模板字面量类型Template Literal Types自 TS 4.1 起字符串字面量类型可以与${...}语法拼接、也能在条件类型里通过infer反向拆解。题目正是围绕这一新特性设计的——它让我们把运行时字符串路径提升到类型层面进行结构化解析。infer 模式匹配K extends \${infer Head}.${infer Rest}属于模板字面量类型的模式匹配用法。TS 会尝试把K的字符串形状与模板对齐.作为分隔符锚点.之前的内容赋给Head之后的内容赋给Rest。对任意多层的路径这个拆分可以不断重复直到Rest中不再出现.。递归条件类型Recursive Conditional TypesGetT[Head], Rest让类型在自身内部被引用。TS 对递归条件类型有实例化深度限制但本挑战的目标路径层级很浅且题目明确不要求数组访问因此不会触碰递归上限。从仓库视角看这个挑战被归类为#utils工具类型与#template-literal模板字面量两大主题正是类型挑战仓库中用字符串类型做文章的典型代表——同一主题下还包括 Trim、Capitalize、CamelCase 等题目它们共享模板字面量 infer 拆分 递归的方法论。如何本地运行与验证仓库根目录为type-challenges见根目录 package.json使用 pnpm 管理开发依赖中 TypeScript 版本为^5.3.3远高于题目所依赖的 4.1 特性下限。你可以把 template.ts 中的实现替换为上述解法然后对照 test-cases.ts 进行验证——测试用例通过type-challenges/utils实现见 utils/index.d.ts导出的Equal与Expect工具做严格的类型相等断言Equal基于函数签名对比判断两个类型是否完全一致ExpectEqual...则要求相等结果必须为字面量true任何近似匹配都会编译失败。运行时可以先执行pnpm install仓库使用pnpm-workspace.yaml工作区type-challenges/utils为 workspace 依赖再通过 tsc 对题目目录做类型检查即可看到用例是否全部通过。小结Typed Get这道 hard 题的价值在于它把点路径字符串这一日常编程中的常见形态用模板字面量类型完整地编码进了类型系统让深层取值在编译期就能获得精确类型并暴露非法路径。实现它的三步曲——先查字面量键、再拆点路径、最后递归下钻——不仅是本题的标准解也是处理一切字符串驱动的类型解析如路由参数、路径拼接、字符串 DSL的通用范式。回顾 test-cases.ts 中的两条边界用例你就能明白为什么先查键、再拆分的顺序是必需的它保证了形如foo.baz这样的真实键名不会被误当作路径解析也保证不存在的路径能干净地收敛到never。赞分享示例工程【免费下载链接】type-challengesCollection of TypeScript type challenges with online judge项目地址https://gitcode.com/GitHub_Trending/ty/type-challenges点击查看免费下载相关推荐TypeScript 类型挑战type-challenges 题 112 之 CapitalizeWords 模板字面量类型实战解析TypeScript 类型挑战type challenges 题 112 之 CapitalizeWords 模板字面量类型实战解析 本文以 question示例工程type-challenges 实战用模板字面量类型实现 Typed Get为嵌套路径访问补全类型推断type challenges 实战用模板字面量类型实现 Typed Get为嵌套路径访问补全类型推断 Typed Get 编号 270难度 hard示例工程攻克Type-Challenges最难关卡270-Typed Get类型挑战完全指南攻克Type Challenges最难关卡270 Typed Get类型挑战完全指南 你是否曾在TypeScript项目中因访问嵌套对象属性而丢失类型信息是示例工程上一篇WeKWS语音唤醒终极指南从零开始构建智能语音唤醒系统下一篇Cortile自定义边缘边距解决面板遮挡问题的完美方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考