TypeScript 05:交叉类型、索引签名、元组与 enum

TypeScript 05:交叉类型、索引签名、元组与 enum

有 JS 基础即可阅读。建议先读第 01~04 课。

1. 交叉类型 &:把多个类型「合体」

A & B 表示「同时满足 A 和 B」------和联合类型 |(满足其一)正好相反:

ts 复制代码
interface Loggable {
  log: () => string
}
interface Timestamped {
  createdAt: number
}

type Entry = Loggable & Timestamped // 且:两个都得有

const e: Entry = {
  log: () => '日志',
  createdAt: 1728800000000,
}

最常用场景:给已有类型追加字段,不用改原类型:

ts 复制代码
interface Person {
  name: string
}

type Admin = Person & { level: number } // Person 的全部 + 新增 level

const admin: Admin = { name: 'Tom', level: 3 }

同名属性类型冲突时,结果是 never(谁也满足不了):{ a: string } & { a: number } 的 a 就是 never。

2. 索引签名:给「键不固定」的对象立规矩

键是动态的(字典类数据)时,没法逐字段列,用索引签名声明「任意键 → 固定值类型」:

ts 复制代码
const scores: { [name: string]: number } = { math: 90, english: 85 }

两个要点:

  • strict 下读取结果带 undefined(键是动态的,TS 不敢保证存在):
ts 复制代码
const math = scores['math'] // number | undefined
math.toFixed(0) // ❌ Object is possibly 'undefined',先判断再用
  • 声明后所有字段必须兼容它 :{ [key: string]: string; version: number } 不合法------version 是 number,违反了「任意键都是 string」

Record<string, number> 是它的泛型等价写法。使用建议:能用具体字段就别用索引签名,它是检查强度最低的对象类型。

3. 元组 tuple:定长、定序的数组

数组 number[] 只约束「每个元素是 number」,不约束长度和位置;元组全部约束:

ts 复制代码
const point: [number, number] = [3, 4] // 恰好两个,都是 number
const bad: [number, number] = [1, '2'] // ❌ 位置类型也要对上

标签元组:给位置起名,可读性大增------多返回值的标准答案:

ts 复制代码
function divide(
  numerator: number,
  denominator: number,
): [quotient: number, remainder: number] {
  return [Math.floor(numerator / denominator), numerator % denominator]
}

const [quotient, remainder] = divide(17, 5)

剩余元素:[name: string, ...points: number[]] = 第一个是名字,后面随便几个数字。

4. enum 与它的现代替代品

enum 是 TS 的私有语法------它会生成一个真实的运行时对象,而不是可剥掉的注解:

ts 复制代码
enum Status {
  Loading = 'loading',
  Success = 'success',
}
console.log(Status.Success) // 'success'------运行时真有这个对象

这正是它的问题:第 01 课说过「TS = JS + 类型,注解运行前被剥掉」,而 enum 违反了这个规则 (在纯 JS 运行环境直接语法报错),还带来一堆历史坑。现代实践更推荐 as const 对象 + 联合类型:

ts 复制代码
const STATUS = {
  loading: 'loading',
  success: 'success',
  error: 'error',
} as const

type Status = (typeof STATUS)[keyof typeof STATUS] // 'loading' | 'success' | 'error'

读法:typeof STATUS 拿到对象的类型,keyof 拿到键的联合,索引访问取到「所有值」的联合------效果和 enum 一致,但全程可剥除、和普通对象一样用。

5. 高频报错速查

报错 人话
Property 'createdAt' is missing in type ... 交叉类型要求字段全齐
Object is possibly 'undefined' 索引签名读取后没判空
Index signature for type 'string' is missing ... 对象字段类型与索引签名不兼容
Source has 3 element(s) but target allows only 2 元组长度超了
Type '"loaded"' is not assignable ... 状态值不在 as const 联合里(多半拼错)
相关推荐
梦de天空一米16881 小时前
【一个重复id让游戏卡在62%,聊聊配置表检查】
前端
ryn483981 小时前
01 一个功能模块,怎么分层才不乱
前端·ai编程·claude
Amos_Web1 小时前
通过 Rspack 源码学 Rust(五):读懂 Result 与问号运算符的错误返回
前端
杨航 AI1 小时前
JEV的用法
java·前端·数据库
Amos_Web1 小时前
Rspack 源码解析(三十五):rspack_error 如何用 miette 渲染带源码定位的错误链
前端
去伪存真1 小时前
高敏资产场景下的大模型协同设计架构
前端·agent
修炼的dance1 小时前
OCR预处理测了108组,纠斜去噪有用,坑在顺序和力度
前端
疯华整猫1 小时前
Android 16 后台常驻适配:用 Trae 搭一套“前台服务 + 加急 Job”的可存活架构
前端
不可能片场1 小时前
AI视频成片 帧间差分把拼接缝照出来
前端·electron
写的都是BUG1 小时前
APK 里的钥匙,一直就放在门口:聊聊加固真正该做什么
前端·算法