ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TypeHero 基础实战:彻底理解 TypeScript 原始数据类型(Primitive Data Types)

TypeHero 基础实战:彻底理解 TypeScript 原始数据类型(Primitive Data Types) 教育前端后端【免费下载链接】typeheroConnect, collaborate, and grow with a community of TypeScript developers项目地址https://gitcode.com/gh_mirrors/ty/typehero点击查看免费下载TypeScript 的一切类型系统都建立在少数几个原始数据类型之上理解它们是理解整个语言的第一步。本文以 TypeHero 仓库中的入门挑战 primitive-data-types 为骨架结合该挑战的 user.ts、tests.ts 与 参考解法讲清number、string、boolean、null、undefined等基础类型的本质并通过逐行修复真实代码掌握类型注解、接口属性和以类型消灭错误的完整工作流。原始数据类型解决的是什么问题原始数据类型primitive data types的能力是整个 TypeScript 的立身之本。问原始类型解决了什么问题几乎等同于问TypeScript 本身解决了什么问题。一个形象的类比是TypeScript 就像一台非常非常聪明的拼写检查器。它在你状态最好的时候帮你写得更快也能在凌晨三点赶论文、身心俱疲时帮你避免拼错单词。拼写检查器之所以有用是因为它内置了英语词汇与语法的规则同理TypeScript 内置了 JavaScript 词汇与语法的高级知识。而 TypeScript 更胜一筹的地方在于你还可以显式声明数据的类型这让 TypeScript 能更准确地判断你正在做的事情到底是一个 bug还是有意为之。从底层逻辑看JavaScript 的值在运行时有自己真实的类别number、string、boolean、null、undefined、symbol、bigint、object而 TypeScript 的静态类型系统正是以这些运行时类别为蓝本建模的。你为数据标注类型就等于给拼写检查器补充了这个词是专有名词、那个词是动词的额外规则错误自然无处遁形。Primitive 在这个语境下到底是什么意思primitive 是技术黑话日常查词典得到的第一个释义很容易误导人1: 与某事物早期进化或历史发展阶段相关的、表示或保存其特性的。按这个释义primitive 岂不成了古老的未开发的其实并不是。继续往下翻词典你会找到一条不那么常见的释义2: 不是由其他任何事物发展或派生而来的。这才是本语境下的准确含义。原始数据类型是信息的基本单位其他一切类型都由它们派生而来。事实上除了极少数例外绝大多数人甚至不知道它们的存在TypeScript 中所有类型都源自原始数据类型。如果你实在好奇那些例外是编译器拥有特殊内建知识的少量构造例如intrinsic关键字和ThisType。它们属于编译器内部的特权类型普通业务代码几乎接触不到可以暂时忽略。原始数据类型长什么样一开始容易混淆的点是原始类型一律用小写字母定义。以下是 TypeHero 入门挑战中需要掌握的基础类型numberJavaScript 只有一种真正的数值类型——IEEE-754 64 位浮点数。因此 TypeScript 不会像其他语言那样提供short、long、uint32、uint16之类的细分类型一切数值统一用number表示。string一个长度可变的字符序列UTF-16 编码。boolean这里有个值得留意的细节——从 TypeScript 内部实现看boolean其实并不是真正的原始类型它只是true与false联合类型的别名。与number、string不同它不会像它们那样发生字面量拓宽widen因此在行为上略有不一致。不过这个问题几乎从不会在实际开发中带来麻烦你完全可以放心把它当作原始类型使用。值得一提的是从集合论Set Theory的角度看TypeScript 对boolean的建模方式反而是更正确的做法。null严格来说它是一个字面量类型但它对应 JavaScript 中特殊的null值因此拥有自己的类型。undefined与null情况相同——它是 JavaScript 中的一个特定值并拥有对应的 TypeScript 类型。此外还有一批更进阶的类型本挑战暂时用不到先作为预告列出symbol、bigint、object、never、unknown、any。最后必须提醒一个经典陷阱Number、String、Boolean、Symbol、Object这些大写变体确实存在但它们指的是 JavaScript 的全局对象构造器与原始类型含义完全不同几乎永远不应该用作类型注解。例如用String注解一个变量会让字符串字面量无法正确收窄还会引入不必要的装箱语义。实战逐行修复 primitive-data-types 挑战该挑战的元信息metadata.json显示它的难度为beginner前置条件为空数组描述是Your TypeScript journey starts with these building blocks.——这是 TypeHero 入门路径的第一站。挑战目标很简单给代码补充原始类型注解直到所有类型错误消失。初始代码一切类型都是隐式推断出来的打开 user.ts初始代码长这样const playSong (artistName, year) { return ${artistName} was released in the year ${year}; }; const artistName Frank Zappa; const age 52; interface Musician { artistName: string; // add the rest } const musicianInfo ({ artistName, age, deceased }) { return ${artistName}, age ${age}${deceased ? (deceased) : }; }; musicianInfo({ artistName, age, deceased: true, });注意几个留白之处playSong的两个参数artistName、year没有注解TypeScript 会推断为any在strict模式下表现为隐式any且这个文件最终会被严格模式编译见下文 tsconfiginterface Musician只写了artistName: string注释明示add the rest——age和deceased属性缺失musicianInfo的解构参数{ artistName, age, deceased }同样没有任何类型。这份文件刻意体现了 challenge-guidelines.md 中不引导证人Avoid Leading The Witness的编写原则不提前把类型写死把决定权留给做题者模拟真实项目中给旧代码补类型的场景。测试文件错误就是需求说明书challenge-guidelines.md 还规定了每个挑战必须有一个tests.ts并且用户写的东西必须放在ExpectEqual块的第一位。本挑战的 tests.ts 因此既是验收标准也是需求的精确描述import { Expect, Equal, Extends } from type-testing; // 正确的用法 playSong(Demiurge, 2012); // ts-expect-error 第一个参数不应该是 number playSong(8675309, 1982); // ts-expect-error 第二个参数不应该是 string playSong(Blood and Thunder, 2006); type test_playSong_Parameters ExpectEqual Parameterstypeof playSong, [string, number] ; type test_playSong_ReturnType ExpectEqual ReturnTypetypeof playSong, string ; type test_age ExpectExtendsnumber, typeof age; type test_artistName ExpectExtendsstring, typeof artistName; type test_Musician_artistName ExpectEqualMusician[artistName], string; type test_Musician_age ExpectEqualMusician[age], number; type test_Musician_deceased ExpectEqualMusician[deceased], boolean; type test_musicianInfo_Parameters ExpectEqual Parameterstypeof musicianInfo[0], Musician ; type test_musicianInfo_ReturnType ExpectEqual ReturnTypetypeof musicianInfo, string ;从这些断言可以读出完整的类型契约playSong的参数必须是[string, number]第一个是歌手名第二个是年份返回类型是stringartistName的类型必须能容纳stringExtendsstring, typeof artistName即typeof artistName必须可赋值给string——由于const声明的字符串字面量会自动拓宽这里实际上要求它是stringage同理必须是numberMusician接口的artistName: string、age: number、deceased: boolean缺一不可musicianInfo的解构参数类型必须恰好等于Musician返回类型是string。测试文件中的两处ts-expect-error注释很关键它们断言这些调用必须是错误的。只有当你给playSong加上正确注解后playSong(8675309, 1982)才会因为第一个参数是 number 而报错、playSong(Blood and Thunder, 2006)才会因为第二个参数是 string 而报错——这两个ts-expect-error才能恰好成立。challenge-guidelines.md 明确要求这类注释必须附带为什么错的说明这两行注释正是示范。参考解法把类型显式写出来参考解法 展示了完整的答案const playSong (artistName: string, year: number) { return ${artistName} was released in the year ${year}; }; const artistName: string Frank Zappa; const age: number 52; interface Musician { artistName: string; age: number; deceased: boolean; } const musicianInfo ({ artistName, age, deceased }: Musician) { return ${artistName}, age ${age}${deceased ? (deceased) : }; }; musicianInfo({ artistName, age, deceased: true, });逐一对照初始代码可以看到四类典型的补类型动作这也是真实项目中给存量代码补类型时最常用的手法给函数参数注解playSong(artistName: string, year: number)。参数类型来自调用处的语义——artistName是字符串、year是年份数字。注解之后Parameterstypeof playSong自动变为[string, number]两个ts-expect-error调用也恰好各自报错。给const变量注解const artistName: string Frank Zappa、const age: number 52。虽然const声明的字面量本来就会被拓宽推断为string/number显式注解让意图更清晰也让Extendsstring, typeof artistName这类断言稳稳通过。补全接口属性Musician增加age: number和deceased: boolean。这正是提示语说的add missing properties to objects。给解构参数注解为接口musicianInfo({ artistName, age, deceased }: Musician)。这让Parameterstypeof musicianInfo[0]恰好等于Musician并且接口与函数签名的修改只需改一处。模板字符串中的三目运算${deceased ? (deceased) : }在deceased: boolean注解下也完全类型安全——这正是boolean原始类型真/假联合语义在实际代码中的体现。严格模式挑战的隐藏门槛每个挑战目录都有自己的 tsconfig.json本挑战开启了三个严格相关选项{ compilerOptions: { strict: true, exactOptionalPropertyTypes: true, noUncheckedIndexedAccess: true } }strict: true会强制隐式 any报错——这正是playSong两个无注解参数必须补类型的原因之一exactOptionalPropertyTypes禁止把undefined隐式塞给可选属性要求类型边界精确noUncheckedIndexedAccess让索引访问的结果包含undefined。这意味着解法不能偷懒用any蒙混过关。challenge-guidelines.md 也明确规定挑战编写中优先使用unknown而非any。所有原始类型注解都必须是精确的string、number、boolean等这对初学者来说是极好的纪律训练。答案如何被自动验证TypeHero 用脚本 validate.ts 自动化验收全部挑战。它的工作方式值得一提脚本将每个挑战的solutions/*.ts内容与tests.ts内容拼接成一个内存中的源文件通过 TypeScript Compiler APIcreateSourceFilecreateProgramgetPreEmitDiagnostics在内存中编译并解析该挑战目录下的tsconfig.json获取编译选项见 validate.ts 的 readConfigFile 调用。随后它输出彩色日志编译无诊断错误 → 绿色✓ challenges/primitive-data-types/solutions/1.ts有任何类型错误 → 红色✗并打印完整诊断信息。同时脚本还会校验每个挑战的metadata.json是否符合 metadata.schema.jsonid、label、description、difficulty、prerequisites、author六个字段全部必填difficulty必须落在beginner/easy/medium/hard/extreme/event枚举内并确保目录名与metadata.json中的id一致、前置条件指向真实存在的挑战 id。所以你的答案本质上要满足的是编译零错误 所有ts-expect-error恰好成立这一双重约束。小结原始类型是你 TypeScript 之旅的第一块基石回到本文开头的问题原始数据类型解决了什么问题答案是——它让拼写检查器级别的类型判断成为可能。number、string、boolean、null、undefined等小写基础类型是类型系统的原子构件接口、函数签名、泛型乃至整套类型体操都从它们派生。通过 TypeHero 的 primitive-data-types 挑战你实际完成了一次给真实代码补类型的完整演练为函数参数标注string/number、为const变量显式注解、补全interface缺失属性、把解构参数注解为接口类型并借助严格模式与 tests.ts 中的ExpectEqual...断言确认每个类型都精确无误。这一套流程正是你在真实工程中驯服 JavaScript 动态性、把 bug 挡在编译期之外的核心能力。赞分享教育前端后端【免费下载链接】typeheroConnect, collaborate, and grow with a community of TypeScript developers项目地址https://gitcode.com/gh_mirrors/ty/typehero点击查看免费下载相关推荐TypeScript 原始类型Primitive Types完整指南7 大基础类型详解与实战TypeScript 原始类型Primitive Types完整指南7 大基础类型详解与实战 导读 primitive types.md 是《The Co文档教程The Concise TypeScript Book深入解析 TypeScript 七大原始类型Primitive TypesThe Concise TypeScript Book深入解析 TypeScript 七大原始类型Primitive Types 本文以《The Conc文档教程TypeScript 原始类型Primitive Types完全指南从 7 大原始类型到类型安全实践TypeScript 原始类型Primitive Types完全指南从 7 大原始类型到类型安全实践 本篇指南以 The Concise TypeScri文档教程上一篇Rerun Boxes2D Archetype 完全指南2D 包围盒的字段、构造与可视化原理下一篇WarcraftHelper终极指南轻松解决魔兽争霸3兼容性问题创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表