TypeScript学习-第3章:复合类型

TypeScript学习-第3章:复合类型

各位前端工友们,上一章咱们搞定了基础类型,相当于摸清了TS世界里的"单个零件"------字符串、数字这些独立个体。但实际开发中,咱们面对的都是"组装件":比如用户列表是多个用户对象组成的集合,一条订单信息里既有字符串姓名,又有数字金额。

这一章咱们就解锁"零件组装技能"------复合类型,核心搞定数组、元组、对象这三大主力,学会给复杂数据结构"贴精准标签"。如果说基础类型是"单兵作战",那复合类型就是"团队协作",掌握它们才能应对真实业务场景。

一、数组类型:同类元素的"整齐队列"

数组咱们在JS里天天用,本质是"一组相同类型的数据集合"。TS给数组加类型约束,就是给这个队列定规矩:"所有人必须是同一种身份",避免混进"异类"。咱们先讲两种声明方式,再聊只读数组的特殊用法。

1. 两种声明方式:各有适配场景

TS里数组有两种标注风格,按需选择即可,核心效果一致:

  • 简洁式:type[] ------日常开发首选,写法清爽。在基础类型后面加[],就表示"该类型的数组"。
typescript 复制代码
    // 数字数组:只能存数字
    let scores: number[] = [90, 85, 95];
    // 字符串数组:只能存字符串
    let names: string[] = ["张三", "李四", "王五"];
    // 错误示例:混存不同类型会标红
    // let mixArr: number[] = [10, "20"]; // 类型不匹配
  • 泛型式:Array<type> ------基于泛型语法(后续章节会深入),适合复杂场景(如嵌套泛型)。写法是Array后跟尖括号,里面填元素类型。
typescript 复制代码
    // 数字数组,和number[]等价
    let scores: Array<number> = [90, 85, 95];
    // 字符串数组,和string[]等价
    let names: Array<string> = ["张三", "李四", "王五"];

小提醒:日常开发用type[]就够了,只有当数组元素是泛型类型(比如后续的Array<Array<number>>二维数组)时,泛型式会更易读。

2. 只读数组:不能修改的"固定队列"

有些场景下,数组创建后就不能增删改元素(比如接口返回的固定列表),这时候就需要"只读数组",相当于给队列上了"锁",禁止任何修改操作。有两种声明方式:

  • readonly type[] ------简洁式,在类型前加readonly

    typescript 复制代码
    // 只读字符串数组
    let readonlyNames: readonly string[] = ["张三", "李四"];
    // 以下操作都会报错:只读数组禁止修改
    // readonlyNames.push("赵六"); // 禁止新增
    // readonlyNames[0] = "张小三"; // 禁止修改元素
    // readonlyNames.pop(); // 禁止删除
  • ReadonlyArray<type>------泛型式,和上面效果完全一致。

    typescript 复制代码
    let readonlyScores: ReadonlyArray<number> = [90, 85];
    // 同样禁止所有修改操作
    // readonlyScores[1] = 90; // 报错

避坑点:只读数组只是"禁止修改元素和长度",如果元素是对象(引用类型),对象内部的属性仍可修改(后续对象部分会细说)。比如readonly {name: string}[],数组不能增删,但里面对象的name可以改。

二、元组(Tuple):固定"人数"和"身份"的队列

数组是"同类元素的可变长队列",而元组是"固定长度、固定类型顺序的严格队列"------相当于规定了"队列里必须有n个人,第1个是A身份,第2个是B身份,不能多也不能少"。这种特性特别适合处理"结构固定的短数据"。

1. 元组的基础用法

声明语法:用[类型1, 类型2, ...]列出每个位置的类型,赋值时必须严格对应------长度一致、类型顺序一致。

复制代码
// 元组:第1个元素是字符串(姓名),第2个是数字(年龄),第3个是布尔(是否成年)
let person: [string, number, boolean] = ["张三", 25, true];

// 正确访问:按索引取对应类型的值
let name: string = person[0];
let age: number = person[1];

// 错误示例:类型不匹配或长度不一致
// let wrongPerson1: [string, number, boolean] = ["李四", "26", true]; // 第2个类型错误
// let wrongPerson2: [string, number, boolean] = ["李四", 26]; // 长度不足

2. 元组的避坑点与实用场景

元组看似简单,但有两个容易踩的坑,还有几个高频实用场景,咱们逐一梳理:

  1. 越界赋值的隐患 :虽然元组长度固定,但在非严格模式下,用push方法新增元素不会报错(严格模式下会警告),但新增元素的类型会被约束为元组所有类型的联合类型。

    typescript 复制代码
    let person: [string, number] = ["张三", 25];
    person.push(30); // 非严格模式下不报错,新增元素必须是string或number
    // person.push(true); // 报错:布尔值不属于元组类型的联合类型`建议:用元组就尽量保持"固定长度",避免手动增删元素,开启严格模式可减少此类隐患。
  2. 可选元素(TS 4.0+支持) :元组也可以有可选元素,用?标记,可选元素必须放在最后。

    复制代码
    // 第3个元素(手机号)是可选的
    let user: [string, number, string?] = ["张三", 25];
    user = ["李四", 26, "13800138000"]; // 也可以补全可选元素
  3. 实用场景:元组适合处理"结构固定的短数据",比如接口返回的坐标([x, y])、用户的账号密码组合、函数返回的多值结果等。

    复制代码
    // 场景1:坐标(x是数字,y是数字)
    let position: [number, number] = [100, 200];
    // 场景2:函数返回多值(成功状态+数据)
    function getUser(): [boolean, {name: string, age: number}] {
      return [true, {name: "张三", age: 25}];
    }

三、对象类型:多类型元素的"组合体"

对象是TS里最常用的复合类型,本质是"键值对的集合",每个键对应一个值,值可以是任意类型(基础类型、复合类型都可)。TS给对象加类型约束,就是给每个"键"指定对应的"值类型",避免乱赋值。

1. 直接声明:快速约束简单对象

对于结构简单的对象,可直接在变量后标注类型,格式为{ 键1: 类型1; 键2: 类型2; ... },多个键值对用分号分隔(逗号也可,习惯用分号更规范)。

typescript 复制代码
// 声明一个用户对象类型:name是字符串,age是数字,isAdult是布尔
let user: {
  name: string;
  age: number;
  isAdult: boolean;
} = {
  name: "张三",
  age: 25,
  isAdult: true
};

2. 可选属性:允许"可有可无"的键

实际开发中,有些对象属性不是必填的(比如用户的手机号、邮箱),这时候用?标记为可选属性------赋值时可以省略该属性,也可以补全。

typescript 复制代码
// 手机号(phone)是可选属性
let user: {
  name: string;
  age: number;
  phone?: string; // 可选属性
} = {
  name: "张三",
  age: 25
  // 省略phone属性,不报错
};

// 也可以补全可选属性
user.phone = "13800138000";

避坑点:访问可选属性时,TS会提示"可能为undefined",需要先判断是否存在再使用,避免运行时错误。

typescript 复制代码
// 正确写法:先判断phone是否存在
if (user.phone) {
  console.log(user.phone.length); // 不报错
}

3. 只读属性:初始化后不能修改的键

有些对象属性初始化后就不能修改(比如用户的ID、订单编号),用readonly标记为只读属性------只能在创建对象时赋值,后续无法修改。

typescript 复制代码
let user: {
  readonly id: number; // 只读属性
  name: string;
} = {
  id: 1001,
  name: "张三"
};

user.name = "张小三"; // 可修改
// user.id = 1002; // 报错:只读属性不能修改

和只读数组类似:只读属性只是"禁止修改属性值",如果属性值是对象(引用类型),对象内部的属性仍可修改。

四、实践:复合类型的嵌套玩法

真实业务场景中,复合类型很少单独使用,大多是"嵌套组合"------比如对象数组、元组嵌套对象、对象里包含数组等。咱们结合两个高频场景,实战演练如何标注类型。

场景1:对象数组(最常用)

比如接口返回的用户列表,是"多个用户对象组成的数组",标注时要先定义单个用户的对象类型,再用数组类型包裹。

typescript 复制代码
// 单个用户的对象类型
type User = {
  id: number;
  name: string;
  age: number;
  phone?: string;
};

// 用户列表:User类型的数组
let userList: User[] = [
  { id: 1001, name: "张三", age: 25 },
  { id: 1002, name: "李四", age: 26, phone: "13800138000" },
  { id: 1003, name: "王五", age: 24 }
];

// 访问嵌套属性:类型安全有提示
console.log(userList[0].name); // 张三(TS自动提示name属性)

场景2:元组嵌套对象

比如处理"用户信息+订单列表"的组合数据,元组第一个元素是用户对象,第二个元素是订单对象数组。

typescript 复制代码
// 订单对象类型
type Order = {
  orderId: string;
  amount: number;
};

// 元组:第1个元素是User对象,第2个是Order数组
let userWithOrders: [User, Order[]] = [
  { id: 1001, name: "张三", age: 25 },
  [
    { orderId: "OD2024001", amount: 99 },
    { orderId: "OD2024002", amount: 199 }
  ]
];

// 访问嵌套数据
console.log(userWithOrders[0].name); // 张三
console.log(userWithOrders[1][0].amount); // 99

场景3:对象嵌套数组+可选属性

比如商品信息,包含基础属性和可选的规格数组。

typescript 复制代码
type Product = {
  id: number;
  name: string;
  price: number;
  specs?: string[]; // 可选的规格数组
};

let product: Product = {
  id: 2001,
  name: "T恤",
  price: 99,
  specs: ["M码", "L码", "XL码"]
};

// 可选数组的安全访问
if (product.specs) {
  console.log(product.specs.length); // 3
}

五、本章小结:复合类型的核心是"结构化约束"

这一章咱们吃透了数组、元组、对象三大复合类型,核心逻辑可以总结为:复合类型是基础类型的"结构化组合",类型标注的本质是给"组合规则"贴标签------数组定"同类元素的队列规则",元组定"固定长度和顺序的队列规则",对象定"键值对的对应规则"。

新手容易踩的坑:一是混淆数组和元组的使用场景(变长用数组,定长用元组);二是忽略可选属性的undefined判断;三是误以为只读复合类型"内部属性也不可修改"。这些都需要通过实践慢慢磨合。

下一章咱们要升级技能,学习函数类型的精准约束------给函数的参数、返回值贴标签,让函数调用更安全、重构更放心。记得多动手写嵌套场景的代码,培养"结构化类型思维",咱们下一章见!

相关推荐
yangyanping201088 小时前
Go语言学习之对象关系映射GORM
jvm·学习·golang
这是个栗子8 小时前
TypeScript(三)
前端·javascript·typescript·react
网络工程小王8 小时前
【Transformer架构详解】(学习笔记)
笔记·学习
倒酒小生10 小时前
今日算法学习小结
学习
醇氧11 小时前
【学习】【说人话版】子网划分
学习
前端精髓11 小时前
移除 Effect 依赖
前端·javascript·react.js
不灭锦鲤11 小时前
网络安全学习(面试)
学习·安全·web安全
lpfasd12312 小时前
TypeScript + Cloudflare 全家桶部署项目全流程
前端·javascript·typescript
行者-全栈开发12 小时前
腾讯地图 Map Skills 快速入门:从零搭建 AI 智能行程规划应用
人工智能·typescript·腾讯地图·ai agent·mcp 协议·map skills·智能行程规划
前端Hardy12 小时前
字节/腾讯内部流出!Claude Code 2026王炸玩法!效率暴涨10倍
前端·javascript·vue.js