mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
1665 字
4 分钟
2026年06月29日 | TypeScript类型体操实战:从入门到放弃
2026-06-29

TypeScript类型体操实战:从入门到放弃#

哎哟,各位爱卿,晚上好呀。本宫瞅着你们这帮小可爱,代码写得那叫一个情真意切,类型定义却跟没穿衣服上街似的,全靠 any 这块遮羞布。皇上前儿个还跟我抱怨,说现在这年轻臣子的代码,连个像样的奏折(类型定义)都看不懂。本宫这就来给你们上上课——《TypeScript类型体操实战:从入门到放弃》,学不会的,就当是给本宫凑个阅读量吧。

第一节:类型声明?那不是有手就行?

啧,本宫知道,你们最爱的就是 let name: string = '皇上' 这种直球。简单,直白,跟喝白开水一样。但问题是,你写的接口和类型别名,怎么跟皇上那些个矫情的圣旨似的,翻来覆去看不懂?比如这个:interface User { name: string; age?: number; [key: string]: any; }。好家伙,age 可有可无我认了,你最后那个索引签名是什么意思?是准备往 User 对象里塞个 “养心殿” 键值对吗?类型声明不是许愿池,什么都能往里扔!求求了,把你那些个乱七八糟的扩展属性,规规矩矩地放进一个单独的 ExtendedInfo 里,别搞“一锅烩”。

第二节:泛型,泛型,还是他妈的泛型!

本宫知道,一提到泛型,你们脑袋就大。function identity<T>(arg: T): T { return arg; },这玩意儿看得懂吧?看得懂个鬼!你们用起来就两个极端:要么一点不敢用,处处硬编码;要么走火入魔,一个 function handle<T extends Record<string, any>, K extends keyof T>(data: T, key: K): T[K] 写出来,别说皇上,连本宫都得眯着眼瞅半天。记住,泛型是类型参数,不是让你把《出师表》全文塞进去。它的精髓是“用的时候再告诉我类型”,而不是“我在定义的时候就给你演一出百变大咖秀”。用之前,先问问自己:这个函数/类,是不是真的对多种类型都一视同仁?是,你就用;不是,就老老实实写具体类型,别装。

第三节:条件类型?三目运算符它爹来了。

T extends U ? X : Y,看着眼熟吧?这不就是三目运算符的亲兄弟吗?只不过它在类型世界里兴风作浪。本宫给你们举个例子,你们写的那些判断类型的小工具,是不是经常这样:type IsString<T> = T extends string ? '是' : '否';。行,本宫夸你,知道用条件类型了。但然后呢?然后你就把这玩意儿到处复制粘贴!合并类型的时候,判断类型的时候,到处都是这种“如果……那么……否则……”的句式。读你的代码,跟批阅一道逻辑绕成麻花的奏折没两样。本宫建议,把复杂的逻辑判断抽离成有名字的、好读的条件类型,别在主线里写一堆“if else”。

第四节:infer?偷东西的高级技巧。

这玩意儿是条件类型里的“卧底”。type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;。看见没,infer R 就是在偷偷地把函数返回值的类型“偷”出来,塞给 R。高级是高级,但你们用起来就像刚学会偷油的小老鼠,见啥偷啥。给一个元组偷第一个元素的类型?偷!给一个对象偷所有 function 类型的值的返回值?偷!偷着偷着,你那代码就变成了“类型侦探事务所”,到处是 infer,连你亲妈(维护者)都看不懂。infer 是把好刀,但别用它来削苹果,杀鸡用牛刀,刀会钝,人会秃。

第五节:实战!给你的API“上户口”

本宫最烦那种,接口返回的数据结构乱七八糟,前端全靠 data as any 或者 data?.a?.b?.c 来猜。来,跟本宫学,用工具类型一劳永逸。假设你有个用户接口:interface ApiUser { id: number; name: string; roles: Array<{ name: string; level: number; }>; }。现在你要创建一个“可编辑的用户类型”,里面 roleslevel 是可选的,且所有字段都可能不存在(因为编辑嘛,可能先清空)。别手写!用 Partial<T>(让所有字段变可选)包一层 PickOmit?错!直接上 Partial<ApiUser>?那 roles 也整个可选了,但里面的结构没变。正确姿势:type EditableUser = { [K in keyof ApiUser]?: K extends 'roles' ? Array<{ name: string; level?: number; }> : ApiUser[K]; }。看见没,映射类型 + 条件类型,一步到位,连 roleslevel 的可选都给你改了。这才是类型体操的正确用法——为了业务逻辑的严谨和代码的可维护性,而不是为了炫技。

第六节:避坑!这些玩意儿快扔了

  1. any 大法好,但会要你命。本宫知道,any 就像奶茶里的珍珠,加一点很爽,加多了齁得慌,最后还容易得病(运行时错误)。除非你是和第三方库的糟糕类型做最后斗争,否则,给本宫把 any 焊死在键盘上!
  2. 断言不是万能的value as SomeType 就是你在对 TypeScript 编译器说:“闭嘴,我知道我在干什么!” 编译器:好的,你开心就好(然后运行时炸了)。优先用类型守卫 if (typeof value === 'string'),让编译器帮你一起检查。
  3. 别把逻辑写进类型里。类型系统是静态的,是给编译器看的。你别指望用 T extends number ? '加法' : '乘法' 这种类型去动态决定运行时的函数调用,那是异想天开。类型是用来约束描述数据的,不是用来执行业务逻辑的。

行了,本宫的碎碎念就到这里。类型体操这玩意儿,练好了是真功夫,能让你的代码固若金汤;练不好,就是给自己的脚绊子,写时一时爽,改时火葬场。记住,所有的“体操”,最终都是为代码的可读性可维护性服务的。别为了体操而体操,皇上可没那么多耐心看你耍杂技。

退朝。本宫得去泡点枸杞了,给你们讲这课,费脑子。

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

2026年06月29日 | TypeScript类型体操实战:从入门到放弃
https://www.yunio.cn/posts/2026-06-29-typescript类型体操实战从入门到放弃/
作者
媚娘
发布于
2026-06-29
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录