☕ 我给 TS 类型做了台"瘦身手术",还顺手用 Docker 起了个 MySQL

写在前面:今天这节课内容有点"杂",但每一样都特别实用。先是热身------用 Docker 三行命令把 MySQL 8.0 跑了起来(为后面的全栈项目准备的"数据库基础设施");然后进入正题,老师开始教 TS 高级工具类型:Pick、Omit、Partial、Record、Exclude、keyof、ReturnType。翻译成人话就是:怎么给类型做"瘦身手术" ------一个接口太大,怎么只挑需要的字段?怎么去掉敏感字段?怎么让所有字段都可选?最爽的是 Omit 的原理------原来它就是 Pick + Exclude + keyof 三个工具拼出来的,我还亲手复刻了一遍。所有代码都是课堂真实代码,一个字符没改。


一、先热个身:Docker 三行命令把 MySQL 跑起来

老师今天的第一件事:本地装个 MySQL,以后全栈项目要用数据库。装 MySQL 的方式不是去官网下载安装包,而是用 Docker 拉镜像、起容器:

bash 复制代码
# 1. 拉镜像(版本不一样)
docker pull mysql

# 2. 起容器:后台运行,名字 mysql-demo,宿主机 3307 端口映射容器内 3306,root 密码 123456
docker run -d --name mysql-demo -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0

这一长串命令,拆开看每个参数都很好懂:

参数 含义
-d 后台运行(detached)
--name mysql-demo 给容器起个名字
-p 3307:3306 宿主机 3307 端口 → 容器内 3306 端口
-e MYSQL_ROOT_PASSWORD=123456 环境变量:root 密码
mysql:8.0 指定镜像版本

注意端口映射的小心机:容器内 MySQL 默认监听 3306,但我们映射到宿主机的 3307------这样不会和本机已有的 3306 端口冲突。

然后进容器、连数据库:

bash 复制代码
# 进入容器的 linux 终端
docker exec -it mysql-demo /bin/bash

# 容器里连接 mysql
mysql -uroot -p123456

docker exec = 钻进正在运行的容器里执行命令;-it 是交互式终端。进了容器就是一个 Linux 终端,mysql 客户端直接连上。今天的"基础设施",就绪。


二、TS 高级类型:给类型做"瘦身手术"

热身结束,正片开始。老师给出了一个很常见的场景:

ts 复制代码
interface User {
    id: number;
    name: string;
    age: number;
    email: string;
}

一个 User 接口有 4 个字段,但不同的场景需要的字段不一样。老师写在代码里的注释是原话:

"有什么特性 一个类型挑选一些你需要的字段,形成新的类型?负责项目,区分度。大型项目类型消费比较多"

翻译一下:大型项目里,同一个类型会被很多地方"消费",但每个地方只需要其中一部分字段。所以,要给类型做"瘦身手术"。

2.1 Pick:挑选需要的字段

ts 复制代码
// 有什么特性 一个类型挑选一些你需要的字段,形成新的类型?
type UserPreview = Pick<User, 'id' | 'name'>
const u: UserPreview = {
    id: 1,
    name: 'qxh',
}

Pick<T, K>:从类型 T 里挑选出 K 指定的字段,组成新类型。列表页只需要 idname,就挑这两个------多了不给,页面更清爽。

2.2 Omit:去掉不想要的字段

ts 复制代码
// Omit 去掉部分字段
type UserSafe = Omit<User, 'email'>

const safeUser : UserSafe = {
    id: 1,
    name: 'qxh',
    age: 11,
}

Omit<T, K>:从 T 里去掉 K 字段。比如 email 是敏感字段,对外返回时直接剔除------瘦身的同时还保护隐私,一举两得。

2.3 Partial:所有字段全部变可选

ts 复制代码
// 所有字段全部变成可选
type PartialUser = Partial<User>;
// patch 修改
const patchUser:PartialUser = {
    name: '嫣嫣',
    age: 18
}
const emptyObj: PartialUser = {};

Partial<T>:把所有字段变成可选的。看注释------"patch 修改"。做 PATCH 接口(部分更新)的时候,用户可能只改 name,不改别的。全量接口用 User,部分更新用 Partial<User>,字段传不传都行,完美适配。

2.4 Record:键值对字典

ts 复制代码
// json key:value Record<键类型, 值类型>
type Dict = Record<string, number>;
const obj: Dict = { a: 1, b: 2 };

type ErrorMsgMap = Record<number, string>;
// http status code
// 1XX 执行中
// 2XX 成功
// 3XX 要跳转
// 4XX 用户错误
// 5XX 服务器端错误
const errorMessage: ErrorMsgMap = {
    400: '请求参数错误',
    401: '未登录,请重新登录',
    403: '权限不足,禁止反问',
    404: '资源找不到',
    500: '服务器内部错误',
}

function getErrMsg(code: number) {
    return errorMessage[code] ?? '未知错误';
}

Record<K, V>:造一个键是 K 类型、值是 V 类型的"字典"。最经典的用法就是 HTTP 状态码映射表------1XX 执行中、2XX 成功、3XX 要跳转、4XX 用户错误、5XX 服务器端错误。查表用 ?? '未知错误' 兜底,查不到就返回默认值,永远不会返回 undefined

2.5 ReturnType:函数返回类型

ts 复制代码
function fn() { return {x:1, y:2}};
type fnReturn = ReturnType<typeof fn>;

ReturnType<typeof fn>:直接把函数的返回类型"抽"出来用。函数返回 {x, y}fnReturn 就是 {x: number, y: number}。函数改返回结构,类型自动跟着变,不用手写第二遍。

2.6 重头戏:Omit 的原理(keyof + Exclude + Pick)

readme 里老师留了一道思考题:

"Omit<T, K> 等价于 Pick<T, Exclude<keyof T, K>> 怎么理解?"

我照着 2.ts 亲手复刻了一遍 Omit:

ts 复制代码
type UserKeys =  keyof User;                 // "id" | "name" | "age" | "email"
type KeepKeys = Exclude<UserKeys, "email">;  // "id" | "name" | "age"
type MyOmitUser = Pick<User, KeepKeys>;      // { id: number; name: string; age: number }

分三步走,readme 里讲得明明白白:

  1. keyof T:拿到类型所有键的联合类型("id" | "name" | "age" | "email"
  2. Exclude:把要剔除的 K 从联合类型里删掉,剩下需要保留的键
  3. Pick:用剩下的键从原类型里挑选字段 → 就实现了 Omit 的效果

这就是 TS 内部 Omit 的等价实现------读源码不如自己拼一遍,拼完就懂了。readme 还留了个小知识点:

"Exclude 处理联合类型,Omit 处理对象接口"

Exclude 是"联合类型"的减法,Omit 是"对象接口"的减法:一个管字符串联合,一个管接口字段,各司其职。


三、总结:TS 工具类型全家桶

工具类型 作用 一句话
Pick<T, K> 挑选字段 列表页只要 id 和 name
Omit<T, K> 去掉字段 email 不要了
Partial<T> 全部可选 PATCH 部分更新
Record<K, V> 键值对字典 HTTP 状态码映射表
Exclude<A, B> 联合类型减法 去掉 email
keyof T 取所有键 "id" | "name" | ...
ReturnType<fn> 函数返回类型 抽出来直接用

工具类型就是给类型做手术的器械:想瘦哪里瘦哪里,想保护哪个字段就保护哪个字段。


写在最后

今天这节课"含金量"很足:Docker 三行命令让 MySQL 跑了起来(以后全栈项目有数据库了),TS 工具类型让我第一次体会到"类型也是可以编程的"------Pick、Omit、Partial、Record 这些工具类型,就像给类型做手术的器械。最惊喜的是亲手复刻出 Omit 的那一刻:原来复杂的高级类型,就是简单工具的排列组合,Pick + Exclude + keyof 拼一拼,Omit 就自己长出来了。

下次面试官问你:"TS 的 Omit 是怎么实现的?Pick 和 Omit 有什么区别?"

你可以淡定地说:

"Omit<T, K> 等价于 Pick<T, Exclude<keyof T, K>>:先用 keyof T 拿到类型所有键的联合类型,再用 Exclude 把要剔除的 K 从联合类型里删掉,最后用 Pick 把剩下的键从原类型中挑选出来。Exclude 处理的是联合类型,Omit 处理的是对象接口。实际使用中,Pick 是从类型里挑选需要的字段(比如列表页只要 id 和 name),Omit 是去掉不需要的字段(比如对外返回时剔除 email),Partial 是把所有字段变成可选(适合 PATCH 部分更新接口),Record 用来构造键值对字典(比如 HTTP 状态码和错误消息的映射表),ReturnType 可以直接抽出函数的返回类型。"

然后看着面试官满意的表情,心里默念:这波,又稳了。


本文所有代码示例均来自课堂学习资料,真实可运行。

相关推荐
leoZ2311 小时前
AI+前端提效- 06 AI辅助调试排错:前端报错、白屏、兼容问题极速定位
前端·人工智能·chatgpt·状态模式·超分辨率重建·openvino·dreamfusion
ji_shuke1 小时前
Vue 3 使用 History 哨兵和 popstate 拦截浏览器返回
前端·javascript·vue.js·history·哨兵·popstate
名字还没想好☜2 小时前
Prometheus 告警实战:写 alerting rules、用 Alertmanager 做路由分组与抑制
运维·前端·javascript·docker·kubernetes·prometheus
郭邯2 小时前
从零撸了一个 HTML 实体编解码工具,顺便聊聊我和 AI 结对编程的日常
前端
樊小肆2 小时前
DeepSeeker-Code源码导读12-Hooks四引擎
前端·人工智能·agent
xm_xm_xm_12 小时前
TypeScript 7 个 核心特性
前端·typescript
mONESY2 小时前
手把手从零复刻「英文网页 AI 翻译」Chrome 插件(新手向)
javascript
pppiii2 小时前
前端并发请求控制:5 种实现方案完整梳理
前端
郑州光合科技余经理3 小时前
本地生活平台搭建:统一订单表与多后台切换怎么拆
java·开发语言·前端·系统架构·uni-app·php·ai编程