20251021-TypeScript八股文整理

116 阅读17分钟

🧩 一、第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页)

对比点JavaScriptTypeScript
类型系统弱类型(运行时报错)强类型(编译时报错)
编译阶段无编译,直接执行有编译,需转译成 JS
语法支持ES5/ES6包含 ES6+,支持接口、泛型、装饰器等
调试方式运行时调试编译时提前发现错误
安全性弱,易出 bug高,更可靠
IDE 支持普通提示智能提示 + 自动补全

🧠 记忆口诀:

“JS 是快手匠人,TS 是持证工程师。”


📗 二、第5页:TypeScript 的数据类型

2.1 什么是数据类型

TypeScript 提供了一套更严格的类型系统。 它在 JavaScript 的基础上,新增了许多类型约束。


✅ 常见类型列表:

类型示例
booleantrue, false
number1, 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 的区别

对比点JavaScriptTypeScript
参数类型动态必须声明类型
返回类型不固定可以声明返回值类型
重载✅ 支持函数重载
类型安全✅ 强类型检查

💡 类比总结:

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 操作类型安全
泛型 hookuseState<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-componentclass 风格组件标准化配方册工厂流水线
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 是安全系统,让一切自动、精准、稳!💪