🧩 一、第1页:TypeScript 的理解
1.1 什么是 TypeScript
一句话总结:
TypeScript 是 JavaScript 的超集(SuperSet) 。 它在 JavaScript 的基础上,增加了类型系统(type system)和编译阶段检查。
🌰 生活类比记忆法:
JS 是“自由散漫的手冲奶茶师傅”,啥都能往里加,糖、奶、珍珠都行。 TS 是“规范化连锁奶茶店”,每种奶茶都有固定配方、比例和名称,不允许随便乱加。
🧠 所以:
- JS:灵活但容易出错;
- TS:严谨但更安全。
📘 代码对比:
JavaScript:
let name = "小可爱";
name = 123; // ✅ 不会报错(但逻辑出错)
TypeScript:
let name: string = "小可爱";
name = 123; // ❌ 报错:类型不匹配
💡 记忆口诀:
“JS 任性自由,TS 严格规范。”
🧱 1.2 特性(第2页)
TypeScript 的核心特性总结如下👇
| 特性 | 含义 |
|---|---|
| 强类型系统 | 每个变量/参数都有明确类型 |
| 编译阶段检测 | 错误在编译时发现,而不是运行时报错 |
| 支持 ES6+ | 可以使用 async/await、class、模块化等语法 |
| 支持面向对象 | 有类(class)、接口(interface)、泛型(generic) |
| 兼容 JS | 任意 JS 文件都能直接改为 TS,逐步过渡 |
| 丰富的 IDE 支持 | 自动补全、类型提示、智能纠错 |
🌸 小白记忆法:
“TypeScript 就像加了安全带的 JavaScript” —— 你还能自由开车,但更不容易翻车 🧠。
🧮 1.2.1 类型注释(Type Annotation)
👉 就是告诉编译器,这个变量是什么类型。
let age: number = 18;
let username: string = "小可爱";
let isOnline: boolean = true;
如果写错类型,会在编译时报错而不是运行时报错。
💡 类比:
像点奶茶时: “奶茶加糖加冰”✅ “奶茶加电线”❌ —— 类型不对,立即警告。
🧱 1.2.2 类型推断(Type Inference)
即使你不写类型,TS 也能根据值自动推断类型。
let count = 10; // 自动认为是 number
count = "hi"; // ❌ 报错:不能把 string 赋给 number
🧠 小记法:
“TS 很聪明,没写类型它也能猜出来。”
🧩 1.2.3 接口(Interface)(第3页)
接口就是定义一套“规范”,规定对象必须包含哪些字段。
interface Person {
name: string;
age: number;
}
const xiaokeai: Person = {
name: "小可爱",
age: 18
};
💡 类比:
“接口”就像公司岗位说明书。
- 岗位:Person
- 要求:必须有 name 和 age 两个属性。
- 少一样就不合格!
🔍 1.3 TypeScript 与 JavaScript 的区别(第4页)
| 对比点 | JavaScript | TypeScript |
|---|---|---|
| 类型系统 | 弱类型(运行时报错) | 强类型(编译时报错) |
| 编译阶段 | 无编译,直接执行 | 有编译,需转译成 JS |
| 语法支持 | ES5/ES6 | 包含 ES6+,支持接口、泛型、装饰器等 |
| 调试方式 | 运行时调试 | 编译时提前发现错误 |
| 安全性 | 弱,易出 bug | 高,更可靠 |
| IDE 支持 | 普通提示 | 智能提示 + 自动补全 |
🧠 记忆口诀:
“JS 是快手匠人,TS 是持证工程师。”
📗 二、第5页:TypeScript 的数据类型
2.1 什么是数据类型
TypeScript 提供了一套更严格的类型系统。 它在 JavaScript 的基础上,新增了许多类型约束。
✅ 常见类型列表:
| 类型 | 示例 |
|---|---|
boolean | true, false |
number | 1, 3.14, -100 |
string | "hello", 'world' |
array | [1,2,3], ["a","b"] |
tuple | [string, number] |
enum | 枚举常量(定义状态) |
any | 任意类型 |
void | 无返回值函数 |
null / undefined | 空类型 |
never | 永远不会返回的函数(抛异常) |
🧠 生活类比记忆:
| TS 类型 | 奶茶店比喻 |
|---|---|
| boolean | 是否加冰 |
| number | 奶茶价格 |
| string | 奶茶名称 |
| array | 奶茶配料表 |
| tuple | [奶茶名, 价格] |
| enum | 菜单项(珍珠奶茶 = 1,椰果奶茶 = 2) |
| any | 神秘特调(随便什么都行) |
| void | 店员喊“出单了!”(不返回结果) |
💡 小口诀:
“布尔真假数文字,数组元组枚举齐, any万能慎使用,void空空无消息。”
🎀 小可爱速背总结(第1~5页)
| 模块 | 内容 | 记忆口诀 |
|---|---|---|
| TypeScript 定义 | JS 超集,带类型系统 | “JS 升级加强版” |
| 核心特性 | 类型安全、编译检查 | “加了安全带的 JS” |
| 区别 | 静态检查 vs 动态执行 | “持证工程师 vs 野路子匠人” |
| 基本类型 | boolean、number、string、array、tuple、enum 等 | “真假数文字,数组元组齐” |
✨ 一句话总结:
TypeScript = “更聪明、更严格、更安全”的 JavaScript。 它帮你提前发现 bug,写出企业级可靠代码 💼。
🧩 一、第6页开始:TypeScript 基础数据类型详解
🟢 2.2.1 boolean(布尔类型)
只有两种值: ✅ true(真) ❌ false(假)
let isOpen: boolean = true;
let isSoldOut: boolean = false;
💡 类比:
“奶茶店今天开门了吗?”
true→ 开门营业false→ 休息关门
记法口诀:
“真开门,假打烊。”
🔢 2.2.2 number(数值类型)
可以是整数、小数、甚至16进制、二进制:
let price: number = 18; // 十进制
let temp: number = 36.5; // 小数
let binary: number = 0b1010; // 二进制
let hex: number = 0x12; // 十六进制
💡 类比:
奶茶的价格、气温、库存数量,全是数字。
记法:
“所有能算钱的,都是 number。”
🧃 2.2.3 string(字符串类型)
文本、文字,都叫字符串。
let tea: string = "珍珠奶茶";
let slogan: string = `欢迎光临 ${tea} 店`;
💡 类比:
奶茶名字、标语、顾客称呼,全是 string。
✨ 模板字符串(反引号 ``)可以嵌入变量, 就像海报上动态展示不同奶茶的名字。
记法:
“凡是能写在引号里的,都是 string。”
🧋 2.2.4 array(数组类型)
表示一组相同类型的数据。
let flavors: string[] = ["原味", "抹茶", "芒果"];
let prices: number[] = [10, 12, 15];
💡 类比:
菜单上奶茶口味列表,或价格表,一整排就是数组。
记法:
“加上 [],数据排排坐。”
🧱 2.2.5 tuple(元组类型)
👉 元组是“定长数组” 每个元素的类型和位置都固定。
let order: [string, number] = ["珍珠奶茶", 18];
💡 类比:
一份订单:[奶茶名字, 价格] 类型顺序不能错!
比如:
order = [18, "珍珠奶茶"]; // ❌ 错误
记法:
“元组有顺序,不能乱坐席。”
🏷️ 2.2.6 enum(枚举类型)
👉 用来表示固定的取值集合,比如状态、类别。
enum CupSize {
Small,
Medium,
Large
}
let myTea = CupSize.Medium;
💡 类比:
奶茶杯型只有三种:小杯、中杯、大杯。 用枚举就能固定选项,防止顾客点“超大无敌杯”😆。
记法:
“选项固定,用枚举限定。”
🌀 2.2.7 any(任意类型)
👉 any 就像“万能奶茶”,什么都能放。
let anything: any = 123;
anything = "奶茶";
anything = true;
💡 类比:
顾客说:“随便帮我调一杯”,于是啥都行,但风险大。
记法:
“any 很爽,用多翻车。”
⚠️ 面试常问:
❗️为什么不推荐大量使用 any? 因为它会让 TypeScript 失去“类型检查”的意义。
🌫️ 2.2.8 null 与 undefined
表示“空”或“没定义”。
let a: null = null;
let b: undefined = undefined;
💡 类比:
某杯奶茶 “还没制作完成” 或 “顾客取消订单”。
记法:
“null 是空杯,undefined 是还没出单。”
🕳️ 2.2.9 void(无返回值)
通常用于函数没有返回值时:
function sayHi(): void {
console.log("欢迎光临~");
}
💡 类比:
店员打招呼 “欢迎光临!” 不需要回传结果。
记法:
“喊一声,没回音。”
🔥 2.2.10 never(永远不会返回)
代表函数永远不会正常结束,比如抛异常或死循环。
function error(): never {
throw new Error("出错啦!");
}
💡 类比:
奶茶机坏了,一直转圈圈,永远出不了奶茶 😭。
记法:
“never = 永不结束。”
🧩 2.2.11 object(对象类型)
对象是键值对结构:
let tea = {
name: "奶盖茶",
price: 20
};
💡 类比:
一杯奶茶的所有属性(名字、价格、配料)集合成一个对象。
记法:
“对象是一杯完整奶茶。”
🧠 二、第10页开始:TypeScript 高级类型引入
前面讲的是“基础奶茶配料”(基本类型), 现在要开始讲“高级调配方案”(高级类型)啦。
🍰 3.1 什么是高级类型
高级类型是对基础类型的“组合、变形和提取”。 比如:
- 联合类型(Union)
- 交叉类型(Intersection)
- 泛型(Generics)
💡 类比:
基础类型是“牛奶、茶、糖”; 高级类型是“奶盖抹茶”、“珍珠奶绿”,是各种搭配混合的产物。
🧩 3.2 常见高级类型(预告)
| 类型 | 用法 |
|---|---|
| Union 联合类型 | 多选一(比如 string 或 number) |
| Intersection 交叉类型 | 合并多个类型为一个 |
| Generic 泛型 | 参数化类型,让函数更通用 |
| Type Alias 类型别名 | 给复杂类型取名字 |
| Interface 扩展 | 继承多个接口 |
💡 比喻记忆:
“联合是或,交叉是和,泛型是模具,别名是标签。”
🎀 小可爱速背总结(第6~10页)
| 类型 | 含义 | 奶茶店比喻 | 记忆口诀 |
|---|---|---|---|
| boolean | 真/假 | 开门了吗 | 真开假闭 |
| number | 数字 | 价格、库存 | 能算钱的 |
| string | 字符串 | 名称、口号 | 引号包文字 |
| array | 数组 | 奶茶口味列表 | 数据排排坐 |
| tuple | 元组 | [名字, 价格] | 顺序不能乱 |
| enum | 枚举 | 杯型选择 | 固定选项 |
| any | 任意类型 | 神秘特调 | 爽但危险 |
| null / undefined | 空值 / 未定义 | 空杯 / 未出单 | 空与未生 |
| void | 无返回值 | 欢迎语 | 喊没回音 |
| never | 永不返回 | 奶茶机坏了 | 永不结束 |
| object | 对象类型 | 一杯奶茶所有属性 | 属性集合 |
🌟 一句话总结:
TypeScript 的类型系统就像奶茶配方表—— 基础原料(number/string)+ 组合工艺(tuple/enum)+ 约束标准(interface) 让每一杯“代码奶茶”都既规范又美味 🧋✨
🧠 一、第11页:TypeScript 高级类型概念
🌟 3.1 什么是高级类型
基础类型(string、number、boolean)就像奶茶的“原料”; 高级类型 = 把这些原料组合、混合、再加工。
💡 你可以理解为:
“一杯奶茶可以是‘珍珠’或‘椰果’, 也可以是‘珍珠+红豆’。 TypeScript 里这些混搭方式,就是高级类型。”
🧩 二、第11~14页:常见高级类型详解
🧃 3.2.1 联合类型(Union Type)
👉 “多选一”的类型,用 | 表示。
let drink: string | number;
drink = "珍珠奶茶"; // ✅
drink = 18; // ✅
drink = true; // ❌ 不行
💡 类比:
顾客可以“点奶茶”或“报价格”, 但不能突然说“我要跳舞”😂。
🧠 小口诀:
“联合是‘或’,选其一就行。”
🍧 3.2.2 交叉类型(Intersection Type)
👉 “多合一”的类型,用 & 表示。
type Milk = { milk: boolean };
type Sugar = { sugar: boolean };
type SweetMilkTea = Milk & Sugar;
const drink: SweetMilkTea = {
milk: true,
sugar: true
};
💡 类比:
一杯“甜奶茶” = 同时有【奶】和【糖】。
🧠 小口诀:
“交叉是‘并’,要全都有。”
🏷️ 3.2.3 类型别名(Type Alias)
👉 给复杂类型取个好记的名字。
type TeaSize = "小杯" | "中杯" | "大杯";
let order: TeaSize = "中杯"; // ✅
order = "特大杯"; // ❌ 报错
💡 类比:
你可以把“规格选项集合”起名叫
TeaSize, 就像奶茶菜单上写“杯型选择”。
🧠 小口诀:
“别名是标签,让类型更简洁。”
🍯 3.2.4 类型断言(Type Assertion)
👉 告诉编译器:“我比你更清楚这个值的类型。”
let drink: any = "奶茶";
let len: number = (drink as string).length;
💡 类比:
你告诉收银员:“放心,这杯我喝过,不会过期!” —— 明确告诉系统它是什么类型。
⚠️ 但要谨慎用,滥用断言就像自己乱改配方,会“炸奶茶机”。
🍹 3.2.5 泛型(Generics)(第13页)
👉 泛型就是“类型占位符”,让函数更通用。 比如一个可以装任何口味奶茶的“通用杯子”。
function orderTea<T>(tea: T): T {
return tea;
}
orderTea<string>("抹茶拿铁"); // ✅
orderTea<number>(18); // ✅
💡 类比:
杯子(函数)能装不同的茶,只要你告诉它是什么茶(类型参数 T)。
🧠 小口诀:
“泛型是模具,装啥都行,但要先声明形状。”
🧱 3.2.6 约束泛型(泛型约束)
👉 限制泛型必须包含某些属性。
interface HasName {
name: string;
}
function greet<T extends HasName>(obj: T) {
console.log("你好," + obj.name);
}
greet({ name: "小可爱" }); // ✅
greet({ age: 18 }); // ❌ 报错
💡 类比:
你要用“会员杯”下单,就必须有会员名字。 没名字的顾客(不符合约束)不让点单!
🎁 3.2.7 条件类型(Conditional Type)(第14页)
👉 根据条件判断类型(就像 if else)。
type DrinkType<T> = T extends "奶茶" ? string : number;
let a: DrinkType<"奶茶">; // string
let b: DrinkType<123>; // number
💡 类比:
如果点的是“奶茶”,我给你文字菜单; 如果点的是“数字编号”,我给你价格表。
🧠 小口诀:
“条件类型像if,用类型来分流。”
🌸 3.3 总结(第15页)
| 类型名 | 功能 | 奶茶店类比 | |
|---|---|---|---|
| 联合(` | `) | 多选一 | |
交叉(&) | 多合一 | 奶茶 + 珍珠 | |
| 类型别名 | 起名 | 奶茶规格表 | |
| 类型断言 | 强制声明类型 | 我知道这杯能喝 | |
| 泛型 | 占位类型 | 通用奶茶杯 | |
| 约束泛型 | 限制范围 | 会员专属杯 | |
| 条件类型 | 动态类型 | 点不同奶茶出不同菜单 |
💡 终极口诀:
“或选交并取,取名断自明,模具装万物,条件可判断。”
🧩 三、第15页:接口 Interface(开篇)
4.1 什么是接口
接口(interface)就是一种 结构约束。 用来规定对象必须具备哪些属性、类型是什么。
interface Tea {
name: string;
price: number;
}
const milkTea: Tea = {
name: "珍珠奶茶",
price: 15
};
💡 类比:
接口就像奶茶配方说明书:
- 必须有“奶茶名”
- 必须有“价格” 否则不合格!
🌸 小可爱总结(第11~15页)
| 模块 | 内容 | 生活类比 | 记忆口诀 |
|---|---|---|---|
| 联合类型 | 多选一 | 奶茶 or 果茶 | 或选其一 |
| 交叉类型 | 多合一 | 奶茶 + 珍珠 | 并且都有 |
| 类型别名 | 给类型取名 | 菜单项命名 | 标签好记 |
| 类型断言 | 强制类型说明 | “我知道这杯能喝” | 少用易翻车 |
| 泛型 | 类型占位 | 通用奶茶杯 | 模具万物装 |
| 约束泛型 | 限制泛型属性 | 会员专属杯 | 有名才能用 |
| 条件类型 | if 判断类型 | 奶茶 or 编号菜单 | 条件分流 |
| 接口 | 对象约束 | 奶茶配方表 | 缺项不合格 |
🧠 一句话总结:
TypeScript 的高级类型就像一间“奶茶定制工坊”: 你可以混合口味(交叉)、自由选择(联合)、加标签(别名)、限定配方(接口), 还可以用万能模具(泛型)打造无限组合! 🍹✨
🧠 一、第16页:接口基础复习
接口(interface) = 一种 约束规则 👉 规定“对象必须包含哪些属性”。
interface User {
name: string;
age: number;
}
💡 类比:
你是奶茶连锁品牌的老板,你要求每个分店的配方文件(User 对象) 必须包含:
- 奶茶名(name)
- 售价(age)
谁少了其中一项,立刻不合格 ❌。
🧃 二、第17页:接口的各种“升级玩法”
🧩 4.2.1 可选属性(?)
有时候某些字段不是必须的,用 ? 标识即可。
interface User {
name: string;
age?: number; // 可选
}
const u1: User = { name: "小可爱" }; // ✅
const u2: User = { name: "小甜心", age: 18 }; // ✅
💡 类比:
奶茶可以选择“是否加冰”,不是每杯都得加。
🧠 记法:
“可选属性像加料,可有可无。”
🔒 4.2.2 只读属性(readonly)
表示这个属性只能赋值一次,之后不能改。
interface User {
name: string;
readonly isOnly: boolean;
}
const user: User = { name: "小可爱", isOnly: true };
user.isOnly = false; // ❌ 报错:只读属性不可修改
💡 类比:
“制作日期”是写死的,打印出来后不能再改。
🧠 记法:
“readonly 就像奶茶封口膜——一旦封上,就不能改料。”
🧱 4.2.3 接口继承(extends)
接口可以从另一个接口继承,复用已有字段。
interface Father {
color: string;
}
interface Son extends Father {
name: string;
age: number;
}
💡 类比:
“父亲配方”是基础奶茶(比如:有颜色 color); “子配方”继承基础再加料(加 name、age)。
🧠 小口诀:
“extends = 在原味上加料。”
🧠 调用示例(图中的黑色代码块)
const fn = (user: Son) => {
console.log(user.color);
console.log(user.age);
}
💡 说明: Son 拥有 Father 的属性(color)和自己的属性(name, age)。 就像“珍珠奶茶”继承了“奶茶”的成分,又多了“珍珠”。
🧾 三、第18~19页:接口的应用场景
接口不仅能定义对象结构,还能约束:
- 函数的参数类型;
- 函数的返回值;
- 类(class)的结构。
🌰 举例:定义函数结构
interface SayHi {
(name: string): string;
}
const fn: SayHi = (name) => {
return "你好," + name;
};
console.log(fn("小可爱")); // 输出:你好,小可爱
💡 类比:
这是“标准化点单函数”, 要求传入一个名字(顾客名),返回问候语(字符串)。
🧠 记法:
“interface 可约束函数输入输出。”
🍹 举例:接口用于类的实现
interface Drink {
name: string;
make(): void;
}
class MilkTea implements Drink {
name = "珍珠奶茶";
make() {
console.log("制作中...");
}
}
💡 类比:
规定所有奶茶类 Drink 必须有:
- 名字(name)
- 制作方法(make)
于是:
“珍珠奶茶类(MilkTea)” 按这个标准执行配方。
🧠 记法:
“接口是标准,类是工厂。”
🧩 四、第20页:接口的进阶应用
这一页展示了:
- 接口可同时约束多个对象;
- 不同接口可组合;
- 可用
extends实现“多层继承”。
interface Basic {
name: string;
}
interface Detail extends Basic {
price: number;
}
const tea: Detail = { name: "抹茶拿铁", price: 25 };
💡 类比:
每个分店奶茶既有基本信息(名字), 也要有售价(价格)。
🧠 小口诀:
“接口像企业标准,可层层继承扩展。”
💡 五、第20页末尾:引出下一章「类(class)」
这一页最后进入下一个重点:
“TypeScript 中类(class)的理解与应用场景”。
类(class)是 面向对象的核心, 和接口配合,就能实现“规范 + 实现”的完整系统。
💡 类比:
“接口是配方说明书,类是奶茶师傅的实际制作过程。”
🧠 小可爱总结(第16~20页)
| 概念 | 含义 | 奶茶店比喻 | 记忆口诀 |
|---|---|---|---|
| interface | 结构约束 | 奶茶配方说明书 | 少一项不合格 |
可选属性 ? | 可有可无的字段 | 是否加冰 | “加料随意” |
只读属性 readonly | 不能修改的字段 | 制作日期封膜 | “封口就锁死” |
继承 extends | 扩展已有接口 | 在原味上加料 | “老配方+新料” |
| 接口约束函数 | 统一参数与返回值 | 标准化点单流程 | “输入输出要规范” |
| 接口配合类 | 规定类必须实现方法 | 奶茶师傅按配方做 | “接口是标准,类是工厂” |
🧋 一句话总结:
接口(interface)是 TypeScript 世界里的“奶茶配方标准书”: 它告诉所有奶茶师(类、对象)该怎么做、加什么料、 不能随便改,还能代代传承(extends)~ 🍵✨
☕ 一、第21页:什么是 Class(类)
🧱 5.1 什么是类
在 TypeScript(或 JS)里, 类(Class)是创建对象的模板。 它能定义:
- 属性(数据)
- 方法(行为)
- 构造函数(初始化逻辑)
class Tea {
name: string;
constructor(name: string) {
this.name = name;
}
make() {
console.log(`${this.name} 制作完成!`);
}
}
const t = new Tea("珍珠奶茶");
t.make(); // 输出:珍珠奶茶 制作完成!
💡 类比:
“类”就像奶茶店的制作流程卡:
- 属性 = 奶茶名
- 构造函数 = 开店时准备原料
- 方法 = 实际制作
🧠 小口诀:
“类是模板,new 是造物机。”
🧃 二、第22页:类的继承(extends)
一个类可以继承另一个类, 这样“子类”就能复用“父类”的属性和方法。
class Drink {
name: string;
constructor(name: string) {
this.name = name;
}
make() {
console.log(`制作 ${this.name}`);
}
}
class MilkTea extends Drink {
addPearl() {
console.log("加珍珠~");
}
}
const mt = new MilkTea("奶茶");
mt.make(); // 制作 奶茶
mt.addPearl(); // 加珍珠~
💡 类比:
“Drink 类”是【通用奶茶制作模板】, “MilkTea 类”继承它,再加上自己的特色“珍珠步骤”。
🧠 小口诀:
“继承就是加料,复用又升级。”
🍯 三、第23页:访问修饰符(public / private / protected)
访问修饰符是 TypeScript 的特色,用来控制“外部是否能访问属性”。
| 修饰符 | 含义 | 奶茶店比喻 |
|---|---|---|
public | 公共的,谁都能访问 | 柜台招牌(顾客可见) |
private | 私有的,只有类内部能用 | 配方机密(员工专用) |
protected | 受保护的,子类能访问但外部不能 | 传授给店长的高级秘方 |
🧩 例子1:public 默认公开
class Father {
public name: string;
constructor(name: string) {
this.name = name;
}
}
const f = new Father("奶茶爹");
console.log(f.name); // ✅ 可访问
💡 类比:
柜台菜单,顾客和员工都能看见。
🔒 例子2:private 私有属性
class Father {
private name: string;
constructor(name: string) {
this.name = name;
}
}
const f = new Father("秘密配方");
console.log(f.name); // ❌ 报错:私有属性不能访问
💡 类比:
“秘密配方表”只有老板看得到,顾客和店员都不能偷看。
🧠 记法:
“private 像保险柜,锁住内部机密。”
🧱 例子3:protected 受保护属性
class Father {
protected name: string;
constructor(name: string) {
this.name = name;
}
}
class Son extends Father {
say() {
console.log(`我继承了父亲的秘方:${this.name}`);
}
}
const s = new Son("珍珠秘方");
s.say(); // ✅ 子类可访问
console.log(s.name); // ❌ 外部访问报错
💡 类比:
父亲把“秘方”传给儿子,但不会公开给外人。
🧠 小口诀:
“protected 给后代,private 不外带。”
🌸 四、第24页:只读属性 readonly
有时候某个值在创建后就不能改,比如“品牌名”。
class Father {
readonly brand: string;
constructor(brand: string) {
this.brand = brand;
}
}
const f = new Father("茶百道");
f.brand = "喜茶"; // ❌ 报错:只读属性不可修改
💡 类比:
品牌名称写在门头上,一旦注册不能改。
🧠 记法:
“readonly = 定生死,不可改。”
🧱 五、第25页:静态属性 static
有时候属性或方法属于“类本身”, 而不是某个对象实例,用 static 修饰。
class Store {
static address: string = "广州天河路";
static showAddress() {
console.log("门店地址:" + Store.address);
}
}
Store.showAddress(); // ✅ 可直接用类名访问
💡 类比:
“总部地址”是整个品牌共有的, 不属于哪一家分店。
🧠 小口诀:
“static 属于总部,不用 new 也能用。”
🧠 小可爱总结(第21~25页)
| 概念 | 作用 | 奶茶店比喻 | 记忆口诀 |
|---|---|---|---|
| class | 定义模板 | 奶茶制作流程卡 | 类是模板,new是造物 |
| extends | 继承父类 | 原味基础 + 新口味 | 加料升级 |
| public | 公开属性 | 菜单栏 | 谁都能看 |
| private | 私有属性 | 秘密配方 | 仅内部可见 |
| protected | 受保护属性 | 父传子秘方 | 后代可见 |
| readonly | 只读属性 | 品牌名 | 一旦注册不可改 |
| static | 静态属性 | 总部信息 | 全局共用 |
🌟 一句话总结:
TypeScript 的“类”体系就像奶茶连锁总部的组织架构:
- Class = 店铺模板
- extends = 直营分店继承总部配方
- private/protected = 秘方权限控制
- readonly = 品牌锁死
- static = 总部通用信息
💬 “接口是规范,类是执行,权限是防泄密。”
🧱 第26页:类的继承与 super 关键字
🧩 父类与子类
继承 (extends) 是子类复用父类的属性和方法的机制。 但是在子类的构造函数中,需要用 super() 调用父类构造函数。
class Father {
constructor(public name: string) {}
say() {
console.log("父类 say:", this.name);
}
}
class Son extends Father {
constructor(name: string, public age: number) {
super(name); // 调用父类构造函数
}
show() {
console.log(`子类 show: ${this.name}, ${this.age} 岁`);
}
}
const s = new Son("小可爱", 18);
s.say(); // 输出:父类 say: 小可爱
s.show(); // 输出:子类 show: 小可爱, 18 岁
💡 解释:
super()是必须的!就像子类开奶茶店前要先“注册加盟总部”。- 没
super,父类的配方(属性)就用不了。
🧠 小记法:
“super 是总部授权书,先拿了才能开分店。”
🍯 第27页:方法重写(Override)
子类可以 重写 父类的方法,以实现自己的逻辑。
class Father {
make() {
console.log("父类:制作经典奶茶");
}
}
class Son extends Father {
make() {
console.log("子类:制作珍珠奶茶");
}
}
const s = new Son();
s.make(); // 输出:子类:制作珍珠奶茶
💡 类比:
“父类的奶茶”是原味; “子类的奶茶”可以改成珍珠版。 逻辑一致,但细节更丰富。
🧠 口诀:
“重写不是推翻,是在原配方上加料。”
🧃 第27~28页:类的应用场景(React/Vue)
在 React/Vue 这类框架中,类常用来封装逻辑、组件、或工具库。
class Props {
constructor(public name: string, public price: number) {}
show() {
console.log(`商品:${this.name}, 价格:${this.price}`);
}
}
const p = new Props("奶盖茶", 25);
p.show(); // 输出:商品:奶盖茶, 价格:25
💡 类比:
这个类就像“商品模板” —— 每个饮品都遵循同样的结构(名称 + 价格 + 展示方法)。
🧠 小口诀:
“组件像类,类像组件。”
🧱 第28页:抽象类 abstract(重点)
抽象类是“不能直接被实例化”的类。 它是给子类“定标准”,由子类去实现。
abstract class Drink {
abstract make(): void; // 抽象方法(只定义,不实现)
prepare() {
console.log("准备原料");
}
}
class MilkTea extends Drink {
make() {
console.log("冲泡奶茶");
}
}
const tea = new MilkTea();
tea.prepare(); // 准备原料
tea.make(); // 冲泡奶茶
💡 类比:
总部(抽象类)提供标准流程:
- 所有店铺都要“准备原料”
- 但每家店要自己决定“怎么冲泡”
🧠 口诀:
“抽象类定标准,子类做实现。”
⚠️ 注意:
- 抽象类不能被直接 new;
- 子类必须实现父类的抽象方法。
🧩 第29页:抽象类的应用场景
抽象类常用于:
- 统一不同业务模块的结构;
- 定义基础逻辑框架,让各子类去定制。
例如👇:
abstract class Controller {
abstract handleRequest(): void;
}
class UserController extends Controller {
handleRequest() {
console.log("处理用户请求");
}
}
class OrderController extends Controller {
handleRequest() {
console.log("处理订单请求");
}
}
💡 类比:
“总部Controller” 制定了规则:
- 每个部门都必须有
handleRequest()方法。 子公司(UserController、OrderController)各自实现细节。
🧠 小口诀:
“统一入口,各店自炒。”
🧊 第29~30页:枚举(enum)
💡 6.1 什么是枚举
枚举就是一组命名的常量值集合。 例如订单状态、支付方式、权限等级等。
enum Status {
Pending,
Paid,
Cancelled
}
let order = Status.Paid;
console.log(order); // 输出:1
💡 类比:
“奶茶订单状态”只有几种情况:
- 制作中
- 已完成
- 已取消
🧠 小口诀:
“枚举列清单,状态不混乱。”
🧃 6.2 枚举的使用
你可以定义自己的名字和值。
enum PayType {
WeChat = "微信",
Alipay = "支付宝",
Card = "会员卡"
}
let pay = PayType.WeChat;
console.log(`支付方式:${pay}`); // 输出:支付方式:微信
💡 类比:
顾客付款方式只能选几种,不允许输入“花呗分期100次”😂。 用枚举能“限定选项”。
🧠 记法:
“枚举 = 固定菜单,不许乱点。”
🧩 6.2.1 数字枚举 vs 字符串枚举
TypeScript 中枚举有两种:
| 类型 | 示例 | 输出 |
|---|---|---|
| 数字枚举 | enum A { X, Y } | 0, 1 |
| 字符串枚举 | enum B { X="x", Y="y" } | “x”, “y” |
💡 类比:
数字枚举像是系统编号; 字符串枚举像菜单名字,更清晰。
💥 6.2.2 反向映射(数字枚举专属)
enum Color {
Red,
Green,
Blue
}
console.log(Color[0]); // Red
💡 类比:
顾客报“1号奶茶”,系统能反查出“红茶”。
🧠 小口诀:
“数字可反查,字符串不行查。”
🌈 第30页总结:枚举的应用场景
| 场景 | 示例 | 枚举作用 |
|---|---|---|
| 状态管理 | 订单状态(Pending, Paid) | 限定值集合 |
| 权限控制 | 管理员、员工、顾客 | 角色常量 |
| 配置管理 | 支付方式、语言类型 | 统一管理选项 |
💡 类比:
就像总部给分店配发统一“状态代码本”。 店员不会乱写“奶茶完成了哦耶”,而是严格用标准枚举值。
💡 小可爱总结(第26~30页)
| 概念 | 含义 | 奶茶店类比 | 记忆口诀 |
|---|---|---|---|
| super | 调父类构造函数 | 总部授权 | “先注册再营业” |
| override | 重写方法 | 改良版奶茶 | “旧方新料” |
| 抽象类 | 定规则不落地 | 总部标准手册 | “总部定规矩,分店去执行” |
| 枚举 enum | 固定选项集合 | 状态/支付方式 | “菜单写死不乱点” |
🌟 一句话总结:
TypeScript 的“类 + 抽象类 + 枚举” = 奶茶集团的“总部制度 + 分店模板 + 状态规范” 写起来严谨、扩展性强、易维护 💼
🧋 一、第31~33页:枚举的进阶(enum)
🧱 6.2.4 异构枚举(重点)
在 TypeScript 中,枚举(enum) 可以同时包含数字与字符串值。 这种混合类型称为 异构枚举。
enum Result {
A = 1,
B = "成功"
}
console.log(Result.A); // 输出:1
console.log(Result.B); // 输出:成功
💡 类比:
你在奶茶店系统中设置“状态码”:
A=1表示下单中(数字类型)B="成功"表示已完成(字符串类型)
🧠 小口诀:
“数字编号 + 文本说明 = 异构枚举。”
🧩 6.3 枚举应用场景(第33页)
枚举在真实项目中非常常用,尤其在 前后端交互 时。
enum Direction {
Up = "上",
Down = "下",
Left = "左",
Right = "右"
}
function move(dir: Direction) {
console.log("移动方向:" + dir);
}
move(Direction.Up); // 输出:移动方向:上
💡 类比:
就像奶茶机器人只有“上、下、左、右”几种运动方向, 用枚举可以确保程序只允许这些选项,不会有人乱传入“斜着飞”。
🧠 小口诀:
“写死选项,用枚举定死它。”
🌟 总结:枚举的三种主要应用
| 场景 | 示例 | 含义 |
|---|---|---|
| 状态标识 | enum OrderStatus | 待支付、已支付、取消 |
| 固定配置 | enum Theme | 白天、黑夜 |
| 动作指令 | enum Direction | 上、下、左、右 |
💡 类比:
枚举就像奶茶店的“固定菜单”: 顾客点单时不能乱写,只能选系统列出的选项 ✅。
☕ 二、第33~35页:TypeScript 函数(Function)
🍰 7.1 什么是函数
在 TypeScript 里,函数和 JavaScript 的函数几乎一样, 但 TS 会多一个“类型系统” 。
也就是说,函数要明确: 1️⃣ 参数的类型 2️⃣ 返回值的类型
🍵 7.2 使用方式
✅ 写法 1:函数声明式
function add(a: number, b: number): number {
return a + b;
}
解释:
a: number, b: number→ 参数类型;: number→ 返回值类型。
💡 类比:
奶茶机接收“两个数字原料”(价格),输出一个“数字总价”。
🧠 小口诀:
“输入有限,输出确定。”
✅ 写法 2:函数表达式(更灵活)
const add = (a: number, b: number): number => a + b;
💡 类比:
就像写“箭头函数”那样, 把函数当成一杯奶茶变量:随时调取、灵活组合。
🍫 7.2.1 可选参数(?)
参数可以是可选的(就像“是否加冰”)。
function makeTea(name: string, sugar?: boolean) {
console.log(name + (sugar ? " 加糖" : " 不加糖"));
}
makeTea("抹茶拿铁"); // 不加糖
makeTea("奶盖茶", true); // 加糖
💡 类比:
顾客点单时,不一定每次都指定“加糖”选项。
🧠 小口诀:
“?像加料,想加就加。”
🍯 7.2.2 默认参数
可以给参数设置默认值(比如默认“加冰”)。
function makeTea(name: string, ice: boolean = true) {
console.log(`${name} ${ice ? "加冰" : "不加冰"}`);
}
makeTea("奶绿"); // 默认加冰
💡 类比:
顾客不说是否加冰,系统默认“加冰”。
🧠 小口诀:
“默认参数,自动补全。”
💎 7.3 函数重载(Overload)
在 TypeScript 中,可以定义 多个同名函数, 根据参数类型不同,执行不同逻辑。
function tea(info: string): string;
function tea(info: number): string;
function tea(info: any): string {
if (typeof info === "string") {
return "奶茶口味:" + info;
} else {
return "奶茶编号:" + info;
}
}
console.log(tea("抹茶")); // 奶茶口味:抹茶
console.log(tea(101)); // 奶茶编号:101
💡 类比:
顾客可以通过“奶茶名”或“编号”点单, 系统会自动识别。
🧠 小口诀:
“重载像多语言菜单,输入不同,输出不同。”
📋 第35页总结:函数类型 & 与 JavaScript 的区别
| 对比点 | JavaScript | TypeScript |
|---|---|---|
| 参数类型 | 动态 | 必须声明类型 |
| 返回类型 | 不固定 | 可以声明返回值类型 |
| 重载 | 无 | ✅ 支持函数重载 |
| 类型安全 | 弱 | ✅ 强类型检查 |
💡 类比总结:
JS 像“随心调奶茶”, TS 像“标准配方制作”—— 输入、输出、步骤都有类型保障,不怕乱来。
💫 小可爱总结(第31~35页)
| 概念 | 含义 | 奶茶店比喻 | 记忆口诀 |
|---|---|---|---|
| 枚举 enum | 固定选项集合 | 菜单/状态码 | 菜单写死不乱点 |
| 异构枚举 | 数字+字符串混合 | 状态码 + 状态名 | 编号+说明 |
| 函数类型 | 限定输入输出 | 标准奶茶机 | 输入有限,输出确定 |
| 可选参数 | 参数可有可无 | 是否加糖 | ?像加料 |
| 默认参数 | 自动补充参数 | 默认加冰 | 不说也有 |
| 函数重载 | 多种输入多种输出 | 名称/编号点单 | 多语言菜单 |
| 区别总结 | TS 比 JS 严谨 | 奶茶有标准流程 | 类型=安全带 |
🌈 一句话总结:
TypeScript 的函数系统就是“智能奶茶机”:
- 可选配料(可选参数)
- 默认口味(默认参数)
- 多种点单方式(函数重载)
- 而枚举菜单确保顾客永远不会点错! 🍹✨
🧋 一、第36页:什么是泛型(Generics)
🌟 概念
泛型的英文是 Generic Type,意思是“通用类型”。 举个例子👇
function echo<T>(value: T): T {
return value;
}
<T>就是泛型变量,代表一个“还不确定”的类型;T可以是任何类型(number、string、boolean...);- 当调用时,TypeScript 会根据传入参数自动判断类型。
echo<string>("珍珠奶茶"); // T = string
echo<number>(123); // T = number
💡 类比:
以前你造的“奶茶机”只能做固定口味(比如只能做奶茶)。 泛型 = “万能奶茶机”,顾客点什么都行,系统会自动匹配。
🧠 小口诀:
“T 是模具,不定死类型。”
🧃 二、第37页:泛型的使用方式
✅ 函数中使用泛型
function identity<T>(arg: T): T {
return arg;
}
console.log(identity("奶绿")); // 奶绿
console.log(identity(99)); // 99
💡 类比:
这台机器不管你放进去的是数字(价格)还是文字(口味), 它都能“原样返回”~
🧠 小记法:
“输入什么,返回什么,T 帮我记类型。”
✅ 泛型数组
function echoArray<T>(list: T[]): T[] {
return list;
}
echoArray<number>([1, 2, 3]);
echoArray<string>(["珍珠", "奶盖"]);
💡 类比:
“泛型数组”就像奶茶机支持“多杯制作”, 不同批次(不同类型的数组)都能自动适配。
🧠 小口诀:
“T[] = 多杯版 T。”
🍰 三、第38页:泛型接口
泛型不仅能在函数里用,也能在接口里定义,让接口更灵活。
interface Box<T> {
value: T;
}
let stringBox: Box<string> = { value: "草莓奶茶" };
let numberBox: Box<number> = { value: 666 };
💡 类比:
“Box” 就像是一个包装盒模板, 里面可以装不同的饮料,不限定类型。
🧠 小口诀:
“接口 + = 万能容器。”
🍩 泛型类(第38页重点)
class Stack<T> {
private list: T[] = [];
push(item: T) {
this.list.push(item);
}
pop(): T {
return this.list.pop()!;
}
}
const s = new Stack<number>();
s.push(10);
s.push(20);
console.log(s.pop()); // 输出 20
💡 类比:
这是一个“杯子堆叠机”: 每次 push = 放一个杯子; pop = 拿出最上面那个杯子。 泛型让这台机器支持不同类型的“杯子”。
🧠 小口诀:
“T 让机器有记忆,每个杯子都类型安全。”
🧱 第39页:泛型约束(extends)
泛型虽然灵活,但太自由也容易“乱套”。 我们可以用 extends 给泛型加点“约束条件”。
function getValue<T extends object, U extends keyof T>(obj: T, key: U) {
return obj[key];
}
const tea = { name: "奶茶", price: 15 };
console.log(getValue(tea, "name")); // 奶茶
💡 类比:
我们限定:
- 只能传“饮品对象”;
- 只能拿“对象中已有的字段”! 就像只能点菜单上存在的饮品。
🧠 小口诀:
“extends 限范围,不乱点菜单。”
🍬 第40页:多类型约束 & 泛型交叉
✅ 多个泛型参数
你可以在一个函数中用多个泛型,比如 <T, U>。
function mix<T, U>(a: T, b: U): [T, U] {
return [a, b];
}
console.log(mix("奶茶", 25)); // ["奶茶", 25]
💡 类比:
奶茶机一次能制作两种组合(饮品名 + 价格), 输出一个“双拼套餐”。
✅ 泛型约束配合接口使用
interface Item {
name: string;
}
function showItem<T extends Item>(obj: T) {
console.log(obj.name);
}
showItem({ name: "乌龙奶茶" }); // ✅
💡 类比:
只有“带 name 属性”的饮品才能上架销售。 泛型约束 = “上架规则检查员”。
🧠 小口诀:
“泛型配 extends,规则不出圈。”
✅ 泛型交叉类型(extends + &)
interface A { name: string; }
interface B { age: number; }
type AB = A & B;
const user: AB = { name: "小可爱", age: 18 };
💡 类比:
“AB” 像是“奶茶 + 甜品”套餐, 把两个接口合并成一个更完整的对象。
🧠 小口诀:
“& 就是合体技。”
🧠 小可爱总结(第36~40页)
| 概念 | 作用 | 奶茶店比喻 | 记忆口诀 |
|---|---|---|---|
| 泛型(T) | 占位符类型 | 万能奶茶机 | 输入什么出什么 |
| 泛型函数 | 函数通用 | 灵活机器 | 自动识别口味 |
| 泛型接口 | 模板容器 | 通用包装盒 | 可装任意类型 |
| 泛型类 | 通用对象模板 | 堆叠奶茶杯机 | T 保类型安全 |
| extends约束 | 限定规则 | 不可乱点菜单 | 规则检查员 |
| 多泛型 | 多输入类型 | 双拼套餐 | mix 套餐组合 |
| 交叉类型 & | 合并多个接口 | 奶茶+甜品套餐 | 合体技 |
🌈 一句话总结:
泛型就是让 TypeScript 拥有“通用智慧”的关键。 它让函数、类、接口像“万能奶茶机”一样灵活又安全。 🧋 没有泛型 = 只能做固定口味; 有了泛型 = 想做什么都行,还不怕出错!
🍰 第41页:什么是装饰器(Decorator)
🧱 概念
装饰器是 TypeScript 提供的一种语法糖,用来 增强类或方法的功能。 (类似 Java 里的 @Autowired,Python 的 @property 那种语法。)
简单说:
它是“包装代码”的工具,可以在不改动原逻辑的前提下, 给类、方法、属性加上额外功能。
🍵 举例理解:
function log(target: any) {
console.log("类被创建:", target);
}
@log
class MilkTea {}
💡 输出:
类被创建: class MilkTea {}
💬 类比解释:
想象你是奶茶店老板, “@log” 就像在每杯奶茶上加个二维码贴纸, 机器扫描时会自动“记录是谁做的这杯奶茶”。
🧠 小口诀:
“不改机器,加贴纸,功能立刻变更强。”
☕ 第42页:装饰器的种类
TS 有 4 大类装饰器👇
| 装饰器类型 | 作用对象 | 举例 |
|---|---|---|
| 类装饰器 | 整个类 | @Controller、@Service |
| 方法装饰器 | 类中的方法 | @Get、@Post |
| 属性装饰器 | 类的属性 | @Autowired |
| 参数装饰器 | 构造函数/方法参数 | @Inject |
🌟 9.2.1 类装饰器
function Animal(target: Function) {
target.prototype.type = "哺乳类";
}
@Animal
class Dog {}
const d = new Dog();
console.log((d as any).type); // 哺乳类
💡 类比:
“@Animal” 像在 Dog 类身上贴上“哺乳类”的标签。 这样所有狗对象都自动带上这个属性。
🧠 小口诀:
“类装饰器 = 给类加统一身份牌。”
🍯 第43页:方法装饰器
✅ 示例
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const old = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`调用方法:${propertyKey}`);
return old.apply(this, args);
};
}
class Cat {
@log
say() {
console.log("喵~");
}
}
new Cat().say();
// 调用方法:say
// 喵~
💡 类比:
“@log” 就像给猫咪说话功能装上麦克风 🎤 每次喵喵叫,都会被系统记录。
🧠 小口诀:
“方法装饰器 = 行为打日志。”
🍩 第44页:属性装饰器
属性装饰器通常用于“控制访问”或“增加额外信息”。
function readOnly(target: any, key: string) {
Object.defineProperty(target, key, {
writable: false,
});
}
class Person {
@readOnly
name = "小可爱";
}
const p = new Person();
p.name = "坏蛋"; // ❌ 报错:只读属性
💡 类比:
“@readOnly” = 给奶茶机贴上“禁止调味”的标签, 一旦定义,后续别人就不能随便改配方。
🧠 小口诀:
“属性装饰器 = 配方锁定。”
🧁 第45页:参数装饰器
参数装饰器能获取“函数参数”的信息,常用于依赖注入。
function logParam(target: any, method: string, index: number) {
console.log(`第 ${index} 个参数被注入到 ${method} 中`);
}
class MilkTea {
make(@logParam name: string) {
console.log("制作奶茶:" + name);
}
}
💡 输出:
第 0 个参数被注入到 make 中
制作奶茶:珍珠奶茶
💡 类比:
“@logParam” 像在点单系统中标记“顾客名”, 方便后台记录是哪位点的这杯奶茶。
🧠 小口诀:
“参数装饰器 = 点单打标。”
🍬 应用场景(第45页)
| 场景 | 装饰器用法 | 说明 |
|---|---|---|
| 日志记录 | @log | 自动打印方法调用 |
| 权限验证 | @Auth | 检查当前用户是否有权限 |
| 数据校验 | @Validate | 检查参数是否合法 |
| IoC 容器 | @Inject | 自动注入依赖对象 |
| Web框架 | @Controller / @Get | 装饰接口或类 |
💡 类比总结:
装饰器像“程序界的奶茶贴纸”:
@log:制作时记录日志@Auth:验证顾客是否会员@readOnly:禁止改配方@Inject:自动接原料
🧠 小可爱记忆表(第41~45页)
| 类型 | 装饰对象 | 奶茶店比喻 | 作用 |
|---|---|---|---|
| 类装饰器 | 整个类 | 给店铺贴“连锁加盟店”牌 | 给类添加元信息 |
| 方法装饰器 | 类方法 | 每次做奶茶都打日志 | 增强函数逻辑 |
| 属性装饰器 | 属性 | 锁定配方 | 保护属性不被改 |
| 参数装饰器 | 函数参数 | 标记顾客信息 | 注入数据或依赖 |
🌈 一句话总结:
TypeScript 装饰器 = “代码的贴纸系统”。 不改底层逻辑,就能灵活增强功能 ✨ 是大型框架(如 NestJS、Angular)中“魔法糖浆”的核心🍯。
🧋 第46~47页:装饰器进阶篇
🧱 9.2.4 访问器装饰器(Accessor Decorator)
📘 概念 访问器(getter/setter)是类中用来 拦截属性读取或赋值 的。 装饰器可以“增强”它,比如加日志或权限控制。
🍵 示例
function log(target: any, prop: string, descriptor: PropertyDescriptor) {
const getter = descriptor.get;
const setter = descriptor.set;
descriptor.get = function () {
console.log("正在获取属性:", prop);
return getter?.call(this);
};
descriptor.set = function (value) {
console.log("正在修改属性:", prop, "新值:", value);
setter?.call(this, value);
};
}
class MilkTea {
private _price: number = 10;
@log
get price() {
return this._price;
}
set price(value: number) {
this._price = value;
}
}
const tea = new MilkTea();
tea.price = 20; // 正在修改属性: price 新值: 20
console.log(tea.price); // 正在获取属性: price
💡 类比:
就像奶茶收银台装了摄像头 🎥: 每次修改价格或读取价格,系统都会自动记录。
🧠 小口诀:
“访问器装饰器 = 属性带监控。”
🍩 9.2.5 装饰器工厂(Decorator Factory)
📘 概念 装饰器工厂是“可以传参的装饰器”。 像定制“不同等级的奶茶杯贴纸”——可加参数灵活控制。
示例
function Tag(type: string) {
return function (target: any) {
console.log(`${target.name} 被标记为:${type}`);
};
}
@Tag("特调奶茶")
class CheeseMilkTea {}
输出:
CheeseMilkTea 被标记为:特调奶茶
💡 类比:
“装饰器工厂” = 奶茶贴纸打印机, 你可以输入参数来定制不同贴纸内容。
🧠 小口诀:
“装饰器 + 工厂 = 可定制贴纸。”
🍰 9.2.6 多装饰器组合
📘 概念 多个装饰器可以叠加使用,形成“装饰器洋葱圈”。 执行顺序:从下往上执行函数,从上往下应用结果。
示例
function A() {
console.log("A: 装饰器执行");
return (target: any) => console.log("A: 应用到", target.name);
}
function B() {
console.log("B: 装饰器执行");
return (target: any) => console.log("B: 应用到", target.name);
}
@A()
@B()
class PearlTea {}
输出:
B: 装饰器执行
A: 装饰器执行
A: 应用到 PearlTea
B: 应用到 PearlTea
💡 类比:
想象你制作珍珠奶茶: 先“执行”是准备配料(糖浆、珍珠), 最后“应用”是把它们一层层倒进杯子里。
🧠 小口诀:
“执行自下而上,应用自上而下。”
🍭 9.3 应用场景(第47页)
| 装饰器类型 | 应用场景 | 奶茶比喻 |
|---|---|---|
| 类装饰器 | 标记组件、服务 | 给机器贴“品牌标签” |
| 方法装饰器 | 打印日志、权限控制 | 记录制作过程 |
| 属性装饰器 | 校验或冻结属性 | 锁定原料配方 |
| 参数装饰器 | 注入依赖 | 自动配原料 |
| 访问器装饰器 | getter/setter监听 | 监控价格修改 |
| 工厂装饰器 | 可传参定制 | 打印不同标签 |
| 多装饰器组合 | 复杂逻辑堆叠 | 奶茶加料分层制 |
☕ 第48~50页:命名空间 vs 模块 🌍
🌟 10.1 模块(Module)
模块是 TypeScript 的“分文件机制”, 就像奶茶连锁店的“不同分店”,每家负责不同部分功能。
示例
// a.ts
export const a = 20;
// b.ts
import { a } from "./a";
console.log(a);
💡 类比:
export是“总部授权分店”,import是“分店进货”。
⚠️ 注意:
- 模块文件默认“独立作用域”,不会污染全局;
- 使用
import/export前提:文件被视为模块(非全局)。
🧠 小口诀:
“模块 = 文件间合作,不串货。”
🧩 10.2 命名空间(Namespace)
📘 概念 命名空间是 在同一个文件中组织代码结构 的方式, 防止变量重名(像给每个奶茶机的操作台分区域)。
示例
namespace FruitTea {
export const name = "草莓奶茶";
export function make() {
console.log("制作 " + name);
}
}
namespace MilkTea {
export const name = "原味奶茶";
export function make() {
console.log("制作 " + name);
}
}
FruitTea.make(); // 制作 草莓奶茶
MilkTea.make(); // 制作 原味奶茶
💡 类比:
“命名空间”就像同一家奶茶店里的两个制作区, 一个专门做果茶,一个专门做奶茶,避免“材料冲突”。
🧠 小口诀:
“命名空间 = 文件内分区。”
⚔️ 10.3 模块 vs 命名空间 区别总结(第50页)
| 对比点 | 模块(Module) | 命名空间(Namespace) |
|---|---|---|
| 作用范围 | 跨文件 | 文件内 |
| 导入导出 | 需要 import/export | 用点访问(A.B) |
| 使用场景 | 大型项目、团队协作 | 小型项目或老代码 |
| 执行环境 | Node / ES 模块体系 | 全局浏览器环境 |
| 类比 | 各地分店 | 店内不同工作区 |
💡 比喻总结:
模块:奶茶总部和分店之间的合作; 命名空间:同一个店铺里的不同柜台协作。
🧠 小口诀:
“模块分城市,命名空间分工区。”
💡 小可爱总结表(第46~50页)
| 知识点 | 概念 | 奶茶比喻 | 记忆口诀 |
|---|---|---|---|
| 访问器装饰器 | 监听 getter/setter | 价格监控摄像头 | 属性带监控 |
| 装饰器工厂 | 可传参装饰器 | 打印自定义贴纸 | 可定制贴纸 |
| 多装饰器组合 | 多层装饰器叠加 | 奶茶加料分层制 | 执行↓应用↑ |
| 模块(Module) | 文件间导入导出 | 各地分店协作 | import/export |
| 命名空间(Namespace) | 文件内组织代码 | 店内分柜协作 | 点号访问 |
🌈 一句话总结:
第46~50页讲的就是: “让奶茶代码分层 + 加标签 + 不乱套” 的秘诀 🧋
- 装饰器:给功能“贴标签”
- 模块:让分店协同
- 命名空间:让柜台各司其职 让 TypeScript 项目像连锁奶茶品牌一样, 既规范又灵活,既好喝又不乱!🍵✨
🧋第51页:命名空间与模块复习
🧩 模块(Module)
模块就像“不同的奶茶分店”,每个店(文件)都负责一部分功能。 用 export 把原料、机器暴露出去,用 import 让别的店调配使用。
// a.ts
export const sugar = "红糖";
export function boil() {
console.log("正在煮糖浆");
}
// b.ts
import { sugar, boil } from "./a";
boil();
console.log(`使用${sugar}制作奶茶`);
💡 类比:
a.ts 就是“红糖制作工坊”, b.ts 是“饮品店”, 它通过
import从工坊进货红糖原料。
🧠 小口诀:
“export 开工坊,import 来调货。”
🧱 命名空间(Namespace)
命名空间适合在同一个文件里组织多个逻辑模块。
namespace Tea {
export const name = "奶茶";
export function make() {
console.log("制作" + name);
}
}
namespace Coffee {
export const name = "咖啡";
export function make() {
console.log("制作" + name);
}
}
Tea.make(); // 制作奶茶
Coffee.make(); // 制作咖啡
💡 类比:
命名空间就像同一家奶茶店里的不同制作区:
- “Tea 区” 负责调茶;
- “Coffee 区” 负责磨豆; 避免混料、互不干扰。
🧠 小口诀:
“namespace = 同店分区;module = 分店合作。”
🔄 对比总结(图表)
| 对比项 | 模块(Module) | 命名空间(Namespace) |
|---|---|---|
| 定义位置 | 不同文件间 | 同一文件内 |
| 依赖机制 | import/export | 点号访问(A.B) |
| 使用场景 | 大型项目 | 小型或早期项目 |
| 类比 | 不同奶茶分店 | 同店不同操作台 |
☕第52~53页:React 项目中使用 TypeScript
💬 11.1 前言
React 默认是用 JavaScript 写的,但当项目变大,就容易出错:
比如 props 类型传错、函数参数不清晰、组件通信混乱……
TypeScript 就像给 React “加上安全头盔 🪖”, 让每个组件、属性、状态都能被类型检查器守护!
🧠 小口诀:
“React + TS = 奶茶店加智能防呆系统。”
🍰 11.2 使用方式(创建项目)
npx create-react-app my-app --template typescript
或者在已有项目中安装:
npm install typescript @types/react @types/react-dom --save-dev
💡 类比:
就像在现有奶茶店里安装“智能秤 + 识别摄像头”, 让每杯奶茶都符合标准比例。
🌟 11.2.1 无状态组件(Function Component)
type Props = {
name: string;
price: number;
};
const MilkTea: React.FC<Props> = ({ name, price }) => (
<div>
{name}: {price} 元
</div>
);
export default MilkTea;
💡 解释:
Props就是组件的“菜单规范”(规定能接收什么原料)。React.FC<Props>表示这个组件会使用这些类型。- 括号内的
{ name, price }解构传入属性。
💡 类比:
“Props” 就像菜单上的要求: 你必须告诉系统“奶茶名”和“价格”, 否则不能出单。
🧠 小口诀:
“Props 定规格,FC 来验货。”
☕ 11.2.2 有状态组件(Class Component)
type Props = { name: string };
type State = { count: number };
class Counter extends React.Component<Props, State> {
state: State = { count: 0 };
render() {
return (
<div>
<p>{this.props.name}:{this.state.count}</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
点我加料!
</button>
</div>
);
}
}
💡 类比:
Props:点单信息(奶茶种类)State:杯中状态(加料次数)setState:往杯子里继续加料 🧋
🧠 小口诀:
“Props 外来料,State 内部料。”
🍩 11.2.3 父子组件传参
type ChildProps = {
name: string;
onOrder: (name: string) => void;
};
const Child: React.FC<ChildProps> = ({ name, onOrder }) => (
<button onClick={() => onOrder(name)}>点 {name}</button>
);
const Parent = () => {
const handleOrder = (item: string) => console.log("下单:", item);
return <Child name="奶茶" onOrder={handleOrder} />;
};
💡 类比:
- “Parent” 就是收银员;
- “Child” 是点单按钮;
- 当顾客点“奶茶”时,
onOrder把结果传回父组件。
🧠 小口诀:
“子发单,父接单。”
🍬第54~55页:React + TS 总结 & 实战建议
✅ 常见类型定义
| 类型 | 示例 | 说明 |
|---|---|---|
| props 类型 | type Props = { name: string } | 定义组件外部输入 |
| state 类型 | type State = { count: number } | 定义内部状态 |
| 事件类型 | onClick: (e: React.MouseEvent) => void | 约束事件回调 |
| 引用类型 | const ref = useRef<HTMLInputElement>(null) | DOM 操作类型安全 |
| 泛型 hook | useState<number>(0) | 状态初始值有类型 |
💡 类比:
TypeScript 给 React 奶茶店配上了“类型标签机”: 每个容器(组件、事件、状态)都贴了正确标签,不会拿错原料。
⚙️ 优势总结
| 优点 | 奶茶比喻 |
|---|---|
| 提高代码安全性 | 杜绝“加错料”事故 |
| 提升团队协作 | 菜单统一规范 |
| 减少运行错误 | 出杯前先称重校验 |
| 自动补全提示 | 智能奶茶机菜单自动联想 |
🧠 小口诀:
“TS 帮 React 从手摇店 → 智能连锁厂。”
🧠 小可爱总结(第51~55页)
| 知识点 | 核心内容 | 奶茶比喻 | 记忆口诀 |
|---|---|---|---|
| 模块 | 文件间导出导入 | 分店合作 | export 开工坊 |
| 命名空间 | 文件内部划区 | 店内分工台 | namespace 分工 |
| React Props | 外部输入 | 点单信息 | Props 定菜单 |
| React State | 内部数据 | 杯中原料 | State 管内料 |
| 事件传递 | 父子通信 | 顾客下单 → 收银接单 | 子发单,父接单 |
| TypeScript 优势 | 类型安全、智能提示 | 自动校验机器 | TS = 智能防呆系统 |
🌈 一句话收尾:
TypeScript 就是给 React 奶茶店装了“智能生产系统”。 所有配料都有标签,所有操作有监控, 再也不会“加错糖、漏加奶”! 🧋✨
🧋第56页:Vue + TypeScript 前言
在传统 Vue2 时代,项目多用 JavaScript。 但后来项目越来越大,变量乱飞、props 写错、methods 参数混乱…… 于是 TypeScript 登场了!
💡 它能帮你:
- 检查类型是否一致;
- 让组件间传参更安全;
- 自动提示 props、data、methods;
- 配合 IDE(VS Code)实现智能补全。
🧠 小口诀:
“Vue + TS = 会说话的奶茶机” ——所有按钮都有标签,不怕按错!
☕第57页:Vue 中使用 TypeScript 的两种方式
✅ 方式 1:使用 <script lang="ts">
在 Vue3 里,你只要在 <script> 标签中加上 lang="ts":
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "HelloTS",
setup() {
const msg: string = "你好,小可爱!";
return { msg };
},
});
</script>
💡 类比:
lang="ts"就像在奶茶店安装“精密称重系统”, 所有原料(变量)必须标清类型(甜度、体积等), 再也不会乱倒!
✅ 方式 2:使用 vue-class-component 装饰器风格(更面向对象)
安装依赖:
npm install vue-class-component vue-property-decorator --save
然后这样写 👇
import { Vue, Component } from "vue-property-decorator";
@Component
export default class Hello extends Vue {
msg: string = "TypeScript 版 Vue!";
}
💡 类比:
这像是“标准化的奶茶配方册”, 让每一杯奶茶的制作(组件)都有清晰规范。
🧠 小口诀:
“class 写组件,像工厂流水线。”
🍵第58页:computed / data / methods
在 Vue2/3 中,我们常写:
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
@Component
export default class Demo extends Vue {
// data
msg: string = "珍珠奶茶";
price: number = 18;
// computed
get info() {
return `${this.msg} 售价 ${this.price} 元`;
}
// methods
changePrice(newPrice: number) {
this.price = newPrice;
}
}
</script>
💡 类比:
data:奶茶原料(数据存放区)computed:前台展示(实时计算后的菜单)methods:员工操作(加料、改价)
🧠 小口诀:
“data 存原料,computed 出菜单,methods 负责搅拌。”
🧁第59页:props(父子传值)
import { Component, Prop, Vue } from "vue-property-decorator";
@Component
export default class MilkTea extends Vue {
@Prop({ type: String, required: true }) readonly name!: string;
@Prop({ type: Number, default: 10 }) readonly price!: number;
showInfo() {
console.log(`${this.name} 售价 ${this.price} 元`);
}
}
💡 类比:
- 父组件:顾客下单 → 传入口味与价格
- 子组件:根据传参自动制作奶茶
@Prop= “点单标签”
🧠 小口诀:
“父点单,子接单;@Prop 定规范。”
🍰第60页:@Watch(监听数据变化)
当数据变化时自动执行回调。
import { Component, Vue, Watch } from "vue-property-decorator";
@Component
export default class WatchDemo extends Vue {
count = 0;
@Watch("count")
onCountChanged(newVal: number, oldVal: number) {
console.log(`数量从 ${oldVal} 变成 ${newVal}`);
}
add() {
this.count++;
}
}
💡 类比:
@Watch就像在奶茶机上装了“液位传感器”: 只要奶茶量变化,系统就能自动记录、触发操作。
🧠 小口诀:
“@Watch = 传感器,监控数据变动。”
🌸 小可爱总结表(第56~60页)
| 知识点 | 功能 | 奶茶比喻 | 记忆口诀 |
|---|---|---|---|
<script lang="ts"> | 启用 TS | 安装智能称重系统 | 精确称重 |
| vue-class-component | class 风格组件 | 标准化配方册 | 工厂流水线 |
| data | 数据存储 | 奶茶原料区 | 存原料 |
| computed | 计算属性 | 自动生成菜单 | 出菜单 |
| methods | 方法操作 | 搅拌/调味动作 | 负责搅拌 |
| @Prop | 接收父组件参数 | 顾客点单 | 子接单 |
| @Watch | 监听变化 | 液位传感器 | 监控变化 |
✨ 一句话记住:
TypeScript 让 Vue 从“小作坊奶茶摊”升级成了“智能化自动茶饮工厂”! 每一份原料、每一杯奶茶、每一条操作都有明确类型与监控系统。🧋
🧋第61页:@Watch(监听器装饰器)
📘 作用
@Watch 用来监听数据变化,当某个变量被修改时,自动执行相应函数。 等价于 Vue 里的 watch: {},只是这里用 TypeScript 装饰器语法写。
🌸 示例代码讲解:
import { Vue, Component, Watch } from 'vue-property-decorator';
@Component
export default class YourComponent extends Vue {
@Watch('child')
onChildChanged(val: string, oldVal: string) {}
@Watch('person', { immediate: true, deep: true })
onPersonChanged1(val: Person, oldVal: Person) {}
@Watch('person2')
onPersonChanged2(val: Person, oldVal: Person) {}
}
💡 分解说明:
| 装饰器部分 | 功能解释 | 奶茶店类比 |
|---|---|---|
@Watch('child') | 监听名为 child 的数据变化 | “有顾客变更订单时提醒我” |
onChildChanged(val, oldVal) | 当值改变时自动调用此方法 | “新订单 vs 旧订单” 比对 |
immediate: true | 一进店就立刻执行一次 | 刚开张立刻盘点库存 |
deep: true | 深度监听(对象内部变化也能捕捉) | 不仅看顾客点单,还观察他们加的配料 |
💬 类比小故事:
假设你是“珍珠奶茶智能店”的老板 👩🍳:
- 顾客点单信息是
person - 你用
@Watch('person')给收银系统加了监控 → 每当顾客修改饮品(比如加糖、少冰),系统都会提醒你。
而 deep: true 相当于:
不仅检测“奶茶换了没”,连“糖量、冰块、加料”变化都能感知 🧊🍬
🧠 记忆口诀:
“@Watch 是监控器,谁变动我就动。”
☕第61~62页:@Emit(事件发射器)
📘 作用
@Emit 装饰器相当于 Vue 里手动写的 this.$emit(), 它能在方法执行时自动触发事件,把数据传递给父组件。
🌰 示例讲解:
import { Vue, Component, Emit } from 'vue-property-decorator';
@Component({})
export default class Some extends Vue {
mounted() {
// 监听 emit 事件
this.$on('emit-todo', function (n) {
console.log(n);
});
// 触发事件
this.emitTodo('world');
}
@Emit()
emitTodo(n: string) {
console.log('hello');
}
}
🪄 执行过程拆解:
1️⃣ mounted() 生命周期中
this.$on('emit-todo', ...)→ 相当于“监听信号”;- 当触发
emitTodo()时,事件名默认为方法名 →'emit-todo'; - 自动调用
$emit('emit-todo', n)。
2️⃣ @Emit()
- 让方法执行时自动触发事件;
- 返回值会作为
$emit的参数; - 可以传参,也可以直接触发。
💡 奶茶店比喻:
@Emit就像“通知系统 📣”;- 顾客点击“下单”按钮时,系统自动发出一个“订单创建”信号;
- 后台(父组件)收到事件,立刻打印订单、准备制作。
🧠 记忆口诀:
“@Emit 发广播,父组件来接单。”
🧁第62页:12.3 小结总结篇
📘 总结文字:
TypeScript 版的 Vue class 写法与 JavaScript 版其实差不多, 区别在于用装饰器语法让结构更清晰、类型更严格。
💡 通俗理解:
以前写 Vue:
export default {
data() { return { name: '奶茶' } },
methods: { sayHi() {} },
}
现在写 TypeScript + 装饰器版:
@Component
export default class MilkTea extends Vue {
name: string = '奶茶';
sayHi() {}
}
👉 差别不大,但 TS 版的:
- 能有类型智能提示;
- 编译时就能报错;
- 更适合大型项目。
💬 奶茶店比喻:
以前是小摊手写账单(容易写错); 现在是智能系统自动核对订单(高效、准确)。
JS → 手工账; TS → 智能收银机 🧾。
🧠 记忆口诀:
“Vue + TS,不是换做法,而是更安全的自动机。”
🌸 小可爱总结表(第61~62页)
| 知识点 | 功能 | 奶茶比喻 | 记忆口诀 |
|---|---|---|---|
| @Watch | 监听数据变化 | 奶茶液位监控系统 | 谁变动我就动 |
| deep / immediate | 深层监听 / 立即执行 | 检查配料变化 / 开店自检 | 深入检测 |
| @Emit | 触发事件 | 顾客下单信号广播 | 发广播父接单 |
| class + 装饰器 | TypeScript 组件语法 | 智能收银系统 | 安全又整齐 |
🌈 一句话记住:
第61~62页讲的,是 Vue + TypeScript 的「智能联动系统」:
@Watch是传感器,监控变化;@Emit是对讲机,通知外部;- TypeScript 是安全系统,让一切自动、精准、稳!💪