diff --git a/.gitignore b/.gitignore index f87da15..f41c5bf 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,8 @@ dist __pycache__ kssbox.egg-info node_modules -*.class \ No newline at end of file +*.class +debug +release +.rustc_info.json +CACHEDIR.TAG diff --git a/js-advanced/design-pattern/README.md b/js-advanced/design-pattern/README.md index 4c36ddf..d89c6ad 100644 --- a/js-advanced/design-pattern/README.md +++ b/js-advanced/design-pattern/README.md @@ -1,5 +1,223 @@ # 设计模式案例实现 -## [参考文档](https://github.com/youngyangyang04/kama-DesignPattern) -[01.单例模式(饿汉)](./01-singleton-hunger.ts) -[01.单例模式(懒汉)](./01-singleton-lazy.ts) \ No newline at end of file +## 参考文档 + +- [卡码网设计模式精讲](https://github.com/youngyangyang04/kama-DesignPattern) +- [UML一一 类图关系 (泛化、实现、依赖、关联、聚合、组合)](https://blog.csdn.net/m0_37989980/article/details/104470064) + +[01.单例模式(饿汉)](./create/01-singleton-hunger.ts) +[01.单例模式(懒汉)](./create/01-singleton-lazy.ts) + +## 创建型模式 + +- 单例模式(Singleton): 分为饿汉模式和懒汉模式,饿汉先 +- 简单工厂模式(不属于 23 钟设计模式):通过 if、else 或 switch 判断,简化了客户端。但是如果要添加新产品,需要修改工厂类代码。 +- 工厂方法模式(factory Method):在简单工厂模式技术上添加抽象工厂和具体工厂,每个具体工厂创建一个具体产品,添加新的产品需要添加新的工厂,而不修改原来的代码。 +- 抽象工厂模式(Abstract Factory) + - 在工厂方法模式基础上,每个工厂可以生产一系列相关的产品。 +- 建造者模式:(Builder) +- 原型模式:Prototype) + +## 结构型 + +- 适配器模式(Adapter) +- 桥接模式(Bridge): 适合笛卡尔积的组合 +- 组合模式(Composite): 组合模式适用于任何需要构建具有部分-整体层次结构的场景,比如组织架构管理、文件系统的文件和文件夹组织等。 +- 装饰者模式(Decorator) +- 外观模式(Facade) +- 享元模式(Flyweight) +- 代理模式(Proxy) + +## 行为型 + +- 观察者模式(Observer) +- 策略模式(Strategy) + - 把不需要外部清楚的细节尽可能封装起来(需要区分if 写在里面还是外面的辨别点。就是外部是否需要请求该细节) + - 往往需要结合 简单工厂模式 简化客户端操作 +- 命令模式(Command) + - 需求对 “行为请求者” 与 ”行为实现者“ 进行松耦合 + - Invoker(服务员)、Receiver(烤肉师傅)、OrderCommand(烤羊肉)、xxxCommand(烤xxx肉) +- 中介者模式(Mediator) :调停者模式。 +- 备忘录模式 (Memento) +- 模板方法模式(Template Method) +- 迭代器模式(Iterator) +- 状态模式 (State) +- 责任链模式(Chain of Responsibility) +- 解释器模式(Interpreter) +- 访问者模式(Visitor) + +## 区别 + +- 简单工厂、工厂方法、抽象工厂的区别 + - 简单工厂模式:一个工厂方法创建所有具体产品 + - 工厂方法模式:一个工厂方法创建一个具体产品 + - 抽象工厂模式:一个工厂方法可以创建一类具体产品 + +- 抽象工厂模式 与 建造者模式的区别 + - 抽象工厂模式:适合创建一系列相关的对象,封装了对象创建的逻辑,便于扩展和管理不同的产品族。 + - 建造者模式:适合构建复杂对象,支持一步一步的构建过程,能灵活地处理不同的配置选项。 + +- 适配器模式和代理模式的区别 + - 适配器模式主要是让不能访问的能访问 + - 代理模式主要是限制访问,或在访问之前或之后做一些其他的事 + +## 注意点 + +- [装饰器模式](./structural/04.decorator.ts)的抽象类的使用 +- [x] [桥接模式](./structural/03.bridge.ts) : 有点难理解,感觉还是太散了,需要在客户端组合。目的是什么?就是方便组装?使用场景呢? + - 代码中的桥接就是两个抽象接口其中一个抽象接口接入到另一个抽象接口中,二者都有对应的实现类,这样就可以编程笛卡尔积组合,进而增强实用性和扩展性。 + - 如果程序设计上出现笛卡尔积的情况时就要考虑采用该设计模式了。如:热的小杯奶茶、热的大杯奶茶、凉的小杯奶茶、凉的大杯奶茶。 +- [ ] [享元模式](./structural/07.flyWeight.ts) 案例不好,理解的不行,需要一个更好的案例。案例 (围棋 内部状态 颜色、外部状态 坐标)。 +- [ ] [命令模式](./behavioral/3.command.ts) 命令模式太难了吧!! + +## 实战点 + +- [ ] [享源模式, studio 的 block 拖动实力化问题](./structural/07.flyWeight.ts) + +## 类关系 + +### 关联和依赖的区别 + +#### 关联:长实线加箭头 + +- 定义:关联表示两个类之间的长期关系,通常是**拥有关系**或**引用关系**。一个类的对象可以通过关联关系访问另一个类的对象。 +- 持续性:关联通常是持久的,也就是说,一个对象在其生命周期中会持续引用另一个对象。 +- 双向或单向:关联可以是双向的或单向的。双向关联表示两个对象可以互相访问,而单向关联则表示只有一个对象可以访问另一个对象。 +- 例子:教师和学生之间的关系。一个教师对象可能包含多个学生对象,而学生对象也可能引用该教师对象(双向关联)。 + + ``` java + class Teacher { + List students; + + } + + class Student { + Teacher teacher; + } + ``` + +#### 依赖:长虚线加箭头 + +- 定义:依赖表示一个类**临时性**地使用或需要另一个类的对象,通常是在某个方法或某个功能的执行过程中,短期地依赖该对象。依赖是一种更松散的关系。 +- 短暂性:依赖关系通常是瞬时的,一个类只是在某个方法或操作中需要另一个类的帮助,执行完该操作后,依赖就结束了。 +- 例子:司机依赖车来驾驶,但并不一定永久拥有某一辆车。依赖只存在于司机开车的时刻。 + +``` java + +class Driver { + void drive(Car car) { + // 司机在需要驾驶的时候依赖车 + car.start(); + } +} + +``` + +### 组合和聚合 + +#### 组合:长实线加实心菱形 + +``` java +// 轮子类,依赖于 Car +class Wheel { + private String position; + + public Wheel(String position) { + this.position = position; + } + + public String getPosition() { + return position; + } +} + +// 车类,组合多个轮子 +class Car { + private List wheels; + + public Car() { + // 车类内部负责创建轮子对象 + wheels = new ArrayList<>(); + wheels.add(new Wheel("Front-Left")); + wheels.add(new Wheel("Front-Right")); + wheels.add(new Wheel("Rear-Left")); + wheels.add(new Wheel("Rear-Right")); + } + + public void showWheels() { + for (Wheel wheel : wheels) { + System.out.println(wheel.getPosition()); + } + } +} + +public class Main { + public static void main(String[] args) { + // 创建车对象 + Car car = new Car(); + car.showWheels(); + + // 当车对象被销毁时,轮子对象也随之销毁 + car = null; + // 无法再访问车的轮子,因为它们被组合在一起,生命周期一同结束 + } +} +``` + +#### 聚合:长实线加空心菱形 + +``` java +// 学生类,生命周期独立于 Classroom +class Student { + private String name; + + public Student(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} + +// 班级类,聚合多个学生 +class Classroom { + private List students; + + // 构造函数接受外部创建的学生对象 + public Classroom(List students) { + this.students = students; + } + + public void showStudents() { + for (Student student : students) { + System.out.println(student.getName()); + } + } +} + +public class Main { + public static void main(String[] args) { + // 学生对象在外部创建 + Student s1 = new Student("Alice"); + Student s2 = new Student("Bob"); + + // 学生对象传入 Classroom + List studentList = new ArrayList<>(); + studentList.add(s1); + studentList.add(s2); + + // 创建班级对象 + Classroom classroom = new Classroom(studentList); + classroom.showStudents(); + + // Classroom 对象被销毁后,学生对象仍然存在 + classroom = null; + System.out.println(s1.getName()); // 输出 "Alice" + } +} +``` + +#### 组合和聚合的特点 + +- 两个方式可以互相转换,如何需要部分依赖整体的生命周期,则使用组合。如果需要独立,则使用聚合 diff --git a/js-advanced/design-pattern/behavioral/1.observer.ts b/js-advanced/design-pattern/behavioral/1.observer.ts new file mode 100644 index 0000000..58a3e22 --- /dev/null +++ b/js-advanced/design-pattern/behavioral/1.observer.ts @@ -0,0 +1,60 @@ +// 小明所在的学校有一个时钟(主题),每到整点时,它就会通知所有的学生(观察者)当前的时间,请你使用观察者模式实现这个时钟通知系统。 +// 注意点:时间从 0 开始,并每隔一个小时更新一次。 + +import { entry } from "../utils"; + +interface ISubject { + add(observer: IObserver): void; + remove(observer: IObserver): void; + notify(msg: string): void; +} + +interface IObserver { + update(msg: string): void; +} + +class Clock implements ISubject { + private observers: IObserver[] + + constructor() { + this.observers = []; + } + + add(observer: IObserver) { + this.observers.push(observer); + } + + remove(observer: IObserver) { + this.observers = this.observers.filter((item) => item!== observer); + } + + notify(msg: string) { + this.observers.forEach((item) => { + item.update(msg); + }); + } +} + +class Student implements IObserver { + name: string; + constructor(name: string) { + this.name = name; + } + update(msg: string) { + console.log(`${this.name} ${msg}`); + } +} + +// @ts-ignore +entry(2, (...args) => { + return (time: number) => { + const timeSubject = new Clock(); + args.forEach((item) => { + timeSubject.add(new Student(item)); + }); + + for (let i = 1; i <= time; i++) { + timeSubject.notify(i.toString()); + } + }; +})("Alice")("Bob")(3); diff --git a/js-advanced/design-pattern/behavioral/10.interpreter/music.ts b/js-advanced/design-pattern/behavioral/10.interpreter/music.ts new file mode 100644 index 0000000..62bc1d5 --- /dev/null +++ b/js-advanced/design-pattern/behavioral/10.interpreter/music.ts @@ -0,0 +1,109 @@ +// 我的规则是O表示音阶‘O1’表示低音阶,‘O2’表示中音阶,‘O3’表示高音阶; +// ‘P’表示休止符,‘CDEFGAB’表示‘Do-Re-Mi-Fa-So-La-Ti’:音符长度1表示一拍,2表示二拍,0.5表示半拍,0.25表示四分之一拍,以此类推. +// 注意:所有的字母和数字都要用半角空格分开。例如上海滩的歌曲第一句,‘浪奔’,可以写成‘O 2 E 0.5 G 0.5 A 3’表示中音开始,演奏的是mi so la。​” + +interface IExpress { + interpreter(content: string): string; +} + +const LevelMap = { + O1: "低音", + O2: "中音", + O3: "高音", +}; + +const BeatMap = { + "3": "三拍", + "2": "二拍", + "1": "一拍", + "0.5": "半拍", + "0.25": "四分之一拍", +}; + +const NoteMap = { + C: "Do", + D: "Re", + E: "Mi", + F: "Fa", + G: "So", + A: "La", + B: "Ti", +}; + +type LevelMapKey = keyof typeof LevelMap; +type BeatMapKey = keyof typeof BeatMap; +type NoteMapKey = keyof typeof NoteMap; + +class MusicLevel implements IExpress { + interpreter(content: LevelMapKey) { + return LevelMap[content]; + } +} + +class MusicBeat implements IExpress { + interpreter(content: BeatMapKey): string { + return BeatMap[content]; + } +} + +class MusicNote implements IExpress { + interpreter(content: NoteMapKey): string { + return NoteMap[content]; + } +} + +class Context { + musicLevel = new MusicLevel(); + musicBeat = new MusicBeat(); + musicNote = new MusicNote(); + rst: string[][] = []; + + interpreter(content: string) { + this.rst = []; + let path: string[] = []; + let preStr = ""; + // const cA = content.split(" ") + // cA.forEach((element) => { + content.split(" ").forEach((element) => { + if (isNaN(Number(element))) { + if (element === "O") { + preStr = element; + path = []; + this.rst.push(path); + } else { + path.push(this.musicNote.interpreter(element as NoteMapKey)); + } + } else { + if (preStr) { + const curStr = (preStr + element) as LevelMapKey; + path.push(this.musicLevel.interpreter(curStr)); + preStr = ""; + } else { + // path.push(this.musicBeat.interpreter(element as BeatMapKey)); + } + } + }); + + return this; + } + + executor() { + this.rst.forEach((path) => { + let line = ""; + path.forEach((ele) => { + line += ele + " "; + }); + console.log(line); + }); + } +} + +class Player { + context = new Context(); + play(content: string) { + this.context.interpreter(content).executor(); + } +} + +const player = new Player(); +player.play("O 2 E 0.5 G 0.5 A 3 O 2 E 0.5 G 0.5 A 3"); diff --git a/js-advanced/design-pattern/behavioral/11.visitor.ts b/js-advanced/design-pattern/behavioral/11.visitor.ts new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/js-advanced/design-pattern/behavioral/11.visitor.ts @@ -0,0 +1 @@ + diff --git a/js-advanced/design-pattern/behavioral/2.strategy.ts b/js-advanced/design-pattern/behavioral/2.strategy.ts new file mode 100644 index 0000000..da10aed --- /dev/null +++ b/js-advanced/design-pattern/behavioral/2.strategy.ts @@ -0,0 +1,62 @@ +// 小明家的超市推出了不同的购物优惠策略,你可以根据自己的需求选择不同的优惠方式。其中,有两种主要的优惠策略: +// 1. 九折优惠策略:原价的90%。 +// 2. 满减优惠策略:购物满一定金额时,可以享受相应的减免优惠。 +// 具体的满减规则如下: +// 满100元减5元 +// 满150元减15元 +// 满200元减25元 +// 满300元减40元 +// 请你设计一个购物优惠系统,用户输入商品的原价和选择的优惠策略编号,系统输出计算后的价格。 + +import { entry } from "../utils"; + +interface Strategy { + algorithm(price: number): void; +} + +class NinePercentDiscount implements Strategy { + algorithm(price) { + console.log(price * 0.9); + } +} + +class FullDiscount implements Strategy { + private priceMap = { + 100: 5, + 150: 15, + 200: 25, + 300: 40, + }; + + algorithm(price) { + console.log(price - this.priceMap[price]); + } +} + +class StrategyContext { + private discountStrategy: Strategy; + + constructor(way) { + switch (way) { + case 1: + this.discountStrategy = new NinePercentDiscount(); + break; + case 2: + this.discountStrategy = new FullDiscount(); + break; + default: + throw "1 or 2"; + } + } + + discount(price) { + this.discountStrategy.algorithm(price); + } +} + +// @ts-ignore +entry(4, (...args) => { + args.forEach(([price, way]) => { + new StrategyContext(way).discount(price); + }); +})([100, 1])([200, 2])([300, 1])([300, 2]); diff --git a/js-advanced/design-pattern/behavioral/3.command/01.base.ts b/js-advanced/design-pattern/behavioral/3.command/01.base.ts new file mode 100644 index 0000000..67e9ff3 --- /dev/null +++ b/js-advanced/design-pattern/behavioral/3.command/01.base.ts @@ -0,0 +1,95 @@ +// 小明去奶茶店买奶茶,他可以通过在自助点餐机上来点不同的饮品,请你使用命令模式设计一个程序,模拟这个自助点餐系统的功能。 + +import { entry } from "../../utils"; + +abstract class Command { + protected receiver: Receiver; + + constructor(receiver: Receiver) { + this.receiver = receiver; + } + + abstract execute(): void; +} + +class Receiver { + milkTea() { + console.log("MileTea is Ready!"); + } + coffee() { + console.log("Coffee is Ready!"); + } + cola() { + console.log("Cola is Ready!"); + } +} + +class MileTeaCommand extends Command { + constructor(receiver: Receiver) { + super(receiver); + } + + execute(): void { + this.receiver.milkTea(); + } +} +class CoffeeCommand extends Command { + constructor(receiver: Receiver) { + super(receiver); + } + + execute(): void { + this.receiver.coffee(); + } +} +class ColaCommand extends Command { + constructor(receiver: Receiver) { + super(receiver); + } + + execute(): void { + this.receiver.cola(); + } +} + +// 服务员 +class Invoke { + private command: Command; + + constructor(command: Command) { + this.command = command; + } + + setOrder(command: Command) { + this.command = command; + } + + invokeCommand() { + this.command.execute(); + } +} + +// @ts-ignore +entry(4, (...args) => { + const machine = new Receiver(); + let waiter: Invoke; + let command: Command; + + args.forEach((type) => { + if (type === "MilkTea") { + command = new MileTeaCommand(machine); + } else if (type === "Coffee") { + command = new CoffeeCommand(machine); + } else if (type === "Cola") { + command = new ColaCommand(machine); + } + + if (!waiter) { + waiter = new Invoke(command); + waiter.invokeCommand(); + } else { + waiter.setOrder(command); + waiter.invokeCommand(); + } + }); +})("MilkTea")("Coffee")("Cola")("MilkTea"); diff --git a/js-advanced/design-pattern/behavioral/3.command/02.bbq.ts b/js-advanced/design-pattern/behavioral/3.command/02.bbq.ts new file mode 100644 index 0000000..0027379 --- /dev/null +++ b/js-advanced/design-pattern/behavioral/3.command/02.bbq.ts @@ -0,0 +1,91 @@ +// 烤肉案例 + +import { entry } from "../../utils"; +// 命令的抽象类 +abstract class Command { + protected receiver: Receiver; // 烤肉师傅 + + constructor(receiver: Receiver) { + this.receiver = receiver; + } + + abstract execute(): void; +} + +// 烤肉师傅 +class Receiver { + bakeMutton() { + console.log("烤羊肉串"); + } + + bakeChickenWing() { + console.log("烤鸡翅"); + } + + action(name: string) { + console.log(`${name} is ready!`); + } +} + +// 烤羊肉串命令 +class BakeMuttonCommand extends Command { + constructor(receiver: Receiver) { + super(receiver); + } + execute(): void { + this.receiver.bakeMutton(); + } +} +// 烤鸡翅命令 +class BakeCheckingWingCommand extends Command { + constructor(receiver: Receiver) { + super(receiver); + } + execute(): void { + this.receiver.bakeChickenWing(); + } +} + +// 服务员 +class Invoke { + private command: Command; + + constructor(command: Command) { + this.command = command; + } + + setOrder(command: Command) { + this.command = command; + } + + invokeCommand() { + this.command.execute(); + } +} + +// @ts-ignore +entry(4, (...args) => { + // 开店前的准备, 提前准备好烤肉师傅和服务员 + const boy = new Receiver(); + // const bakeMutton1 = new BakeMuttonCommand(boy); + // const bakeMutton2 = new BakeMuttonCommand(boy); + // const bakeChickenWing = new BakeCheckingWingCommand(boy) + let girl: Invoke; + let command: Command; + + args.forEach((type) => { + if (type === "bakeMutton") { + command = new BakeMuttonCommand(boy); + } else { + command = new BakeCheckingWingCommand(boy); + } + + if (!girl) { + girl = new Invoke(command); + girl.invokeCommand(); + } else { + girl.setOrder(command); + girl.invokeCommand(); + } + }); +})("bakeMutton")("Coffee")("Cola")("bakeMutton"); diff --git a/js-advanced/design-pattern/behavioral/4.mediator.ts b/js-advanced/design-pattern/behavioral/4.mediator.ts new file mode 100644 index 0000000..99e8ae5 --- /dev/null +++ b/js-advanced/design-pattern/behavioral/4.mediator.ts @@ -0,0 +1,71 @@ +// 小明正在设计一个简单的多人聊天室系统,有多个用户和一个聊天室中介者,用户通过中介者进行聊天,请你帮他完成这个系统的设计。 + +import { entry } from "../utils"; + +abstract class Colleague { + private name: string; + + get cname() { + return this.name; + } + + constructor(name: string) { + this.name = name; + } + + send(msg: string) { + console.log(`${this.name} received: ${msg}`); + } +} + +abstract class Mediator { + protected colleagues: Colleague[] = []; + + constructor(...colleagues: Colleague[]) { + this.addColleague(...colleagues); + } + + addColleague(...colleagues: Colleague[]) { + this.colleagues.push(...colleagues); + } + + abstract notify(name: string, msg: string): void; +} + +class ChatRoomMediator extends Mediator { + constructor(...colleagues: Colleague[]) { + super(...colleagues); + } + + notify(name: string, msg: string) { + this.colleagues.forEach((item) => { + if (item.cname !== name) { + item.send(msg); + } + }); + } +} + +class UserColleague extends Colleague { + constructor(name: string) { + super(name); + } +} + +// @ts-ignore +entry(3, (...args) => { + const chatRoom = new ChatRoomMediator(); + args.forEach((uname) => { + chatRoom.addColleague(new UserColleague(uname)); + }); + + function dfs([name, msg]: [string, string]) { + chatRoom.notify(name, msg); + return dfs; + } + + return dfs; +})("User1")("User2")("User3")(["User1", "Hello_All!"])(["User2", "Hi_User1!"])([ + "User3", + "How_is_everyone?", +]); diff --git a/js-advanced/design-pattern/behavioral/5.memento/01.base.ts b/js-advanced/design-pattern/behavioral/5.memento/01.base.ts new file mode 100644 index 0000000..1e16945 --- /dev/null +++ b/js-advanced/design-pattern/behavioral/5.memento/01.base.ts @@ -0,0 +1,88 @@ +// 小明正在设计一个简单的计数器应用,支持增加(Increment)和减少(Decrement)操作,以及撤销(Undo)和重做(Redo)操作,请你使用备忘录模式帮他实现。 + +import { entry } from "../../utils"; + +// 备忘录 +class Memento { + private state: string; + + getState() { + return this.state; + } + + constructor(state: string) { + this.state = state; + } +} + +// 发起人 +class Originator { + private state: string; + constructor(state: string) { + this.state = state; + } + + setState(state: string) { + this.state = state; + } + + createMemento() { + return new Memento(this.state); + } + + setMemento(memento: Memento) { + this.state = memento.getState(); + } + + // 通过备忘录恢复状态 + restoreFromMemento(memento: Memento) { + this.state = memento.getState(); + } + + show() { + console.log(this.state); + } +} + +// // 管理者 +// class Caretaker { +// private mementos: Memento[] = []; +// addMemento(memento: Memento) { +// this.mementos.push(memento); +// } + +// getMemento(idx: number) { +// // return this.mementos. +// } +// } + +// 管理者 +class Caretaker { + private memento: Memento; + + constructor(memento: Memento) { + this.memento = memento; + } + + addMemento(memento: Memento) { + this.memento = memento; + } + + getMemento() { + return this.memento; + } +} + +(function () { + let originator = new Originator("on"); + originator.show(); + + const caretaker = new Caretaker(originator.createMemento()) + originator.setState('off'); + originator.show(); + + originator.setMemento(caretaker.getMemento()); + originator.show(); +})(); + + diff --git a/js-advanced/design-pattern/behavioral/5.memento/01.counter.ts b/js-advanced/design-pattern/behavioral/5.memento/01.counter.ts new file mode 100644 index 0000000..1a51b64 --- /dev/null +++ b/js-advanced/design-pattern/behavioral/5.memento/01.counter.ts @@ -0,0 +1,96 @@ +// 小明正在设计一个简单的计数器应用,支持增加(Increment)和减少(Decrement)操作,以及撤销(Undo)和重做(Redo)操作,请你使用备忘录模式帮他实现。 + +class CounterMemento { + private state: number; + + constructor(state: number) { + this.state = state; + } + + getState() { + return this.state; + } +} + +class Counter { + private state: number; + private redoAction = ""; + private counterCaretaker: CounterCaretaker; + constructor(state: number, counterCaretaker: CounterCaretaker) { + this.state = state; + this.counterCaretaker = counterCaretaker; + } + + increment() { + this.counterCaretaker.addMemento(new CounterMemento(this.state)); + this.state += 1; + this.redoAction = "INCREMENT"; + } + + decrement() { + this.counterCaretaker.addMemento(new CounterMemento(this.state)); + this.state -= 1; + this.redoAction = "DECREMENT"; + } + + undo() { + const state = this.counterCaretaker.getMemento()?.getState(); + if (state) { + this.state = state; + } + this.redoAction = "UNDO"; + } + + // 这里实现的是重复上一次执行的命令 + redo() { + if (this.redoAction === "INCREMENT") { + this.increment(); + } else if (this.redoAction === "DECREMENT") { + this.decrement(); + } else if (this.redoAction === "UNDO") { + this.undo(); + } else { + throw "error action"; + } + } + + createMemento() { + return new CounterMemento(this.state); + } + + setMemento(memento: CounterMemento) { + this.state = memento.getState(); + } + + restoreFromMemento(memento: CounterMemento) { + this.state = memento.getState(); + } + + show() { + console.log(this.state); + } +} + +class CounterCaretaker { + private actionStack: CounterMemento[] = []; + + addMemento(memento: CounterMemento) { + this.actionStack.push(memento); + } + + getMemento() { + return this.actionStack.pop(); + } +} + +(function () { + const caretaker = new CounterCaretaker(); + let originator = new Counter(0, caretaker); + + (function doIt(action: string) { + originator[action](); + originator.show(); + + return doIt; + })("increment")("increment")("decrement")("undo")("redo")("increment"); +})(); diff --git a/js-advanced/design-pattern/behavioral/5.memento/02.game.ts b/js-advanced/design-pattern/behavioral/5.memento/02.game.ts new file mode 100644 index 0000000..7f1abdb --- /dev/null +++ b/js-advanced/design-pattern/behavioral/5.memento/02.game.ts @@ -0,0 +1,106 @@ +// 小明正在设计一个简单的计数器应用,支持增加(Increment)和减少(Decrement)操作,以及撤销(Undo)和重做(Redo)操作,请你使用备忘录模式帮他实现。 + +// 备忘录 +class RoleMemento { + private blood: number; + private atk: number; + private defense: number; + + constructor(blood: number, atk: number, defense: number) { + this.blood = blood; + this.atk = atk; + this.defense = defense; + } + + getState() { + const { blood, atk, defense } = this; + return { blood, atk, defense }; + } +} + +// 发起人(业务对象) +class GameRole { + private blood: number; + private atk: number; + private defense: number; + + constructor(blood: number, atk: number, defense: number) { + this.blood = blood; + this.atk = atk; + this.defense = defense; + } + + setState(blood: number, atk: number, defense: number) { + this.blood = blood; + this.atk = atk; + this.defense = defense; + } + + createMemento() { + const { blood, atk, defense } = this; + return new RoleMemento(blood, atk, defense); + } + + setMemento(memento: RoleMemento) { + const { blood, atk, defense } = memento.getState(); + this.blood = blood; + this.atk = atk; + this.defense = defense; + } + + // 通过备忘录恢复状态 + restoreFromMemento(memento: RoleMemento) { + const { blood, atk, defense } = memento.getState(); + this.blood = blood; + this.atk = atk; + this.defense = defense; + } + + show() { + const { blood, atk, defense } = this; + console.log(`blood: ${blood}, atk: ${atk}, defense: ${defense}, `); + return { blood, atk, defense }; + } +} + +// 管理者 +class RoleStateCaretaker { + private mementos: RoleMemento[] = []; + + constructor(memento: RoleMemento) { + this.mementos.push(memento); + } + + addMemento(memento: RoleMemento) { + this.mementos.push(memento); + } + + getMemento(i: number) { + return this.mementos[i]; + } +} + +(function () { + let index = -1; + let originator = new GameRole(100, 100, 100); + originator.show(); + + const roleStateCaretaker = new RoleStateCaretaker(originator.createMemento()); + index++; + + originator.setState(50, 50, 50); + roleStateCaretaker.addMemento(originator.createMemento()); + index++; + originator.show(); + + originator.setState(0, 0, 0); + originator.show(); + + originator.restoreFromMemento(roleStateCaretaker.getMemento(index)); + index--; + originator.show(); + + originator.restoreFromMemento(roleStateCaretaker.getMemento(index)); + index--; + originator.show(); +})(); diff --git a/js-advanced/design-pattern/behavioral/6.template-method.ts b/js-advanced/design-pattern/behavioral/6.template-method.ts new file mode 100644 index 0000000..1403f09 --- /dev/null +++ b/js-advanced/design-pattern/behavioral/6.template-method.ts @@ -0,0 +1,84 @@ +// 小明喜欢品尝不同类型的咖啡,她发现每种咖啡的制作过程有一些相同的步骤,他决定设计一个简单的咖啡制作系统,使用模板方法模式定义咖啡的制作过程。系统支持两种咖啡类型:美式咖啡(American Coffee)和拿铁(Latte)。 + +import { entry } from "../utils"; + +// 咖啡制作过程包括以下步骤: + +// 1. 研磨咖啡豆 Grinding coffee beans + +// 2. 冲泡咖啡 Brewing coffee + +// 3. 添加调料 Adding condiments + +// 其中,美式咖啡和拿铁的调料添加方式略有不同, 拿铁在添加调料时需要添加牛奶Adding milk + +abstract class AbstractTemplate { + coffeeName: string; + + constructor(coffee: string) { + this.coffeeName = coffee; + } + templateMethod() { + console.log(`Making ${this.coffeeName}:`); + this.grindingCoffeeBeans(); + this.brewingCoffee(); + this.addingCondiments(); + console.log(); + } + + abstract grindingCoffeeBeans(): void; + abstract brewingCoffee(): void; + abstract addingCondiments(): void; +} + +class AmericaCoffee extends AbstractTemplate { + constructor() { + super("American Coffee"); + } + + grindingCoffeeBeans(): void { + console.log("Grinding coffee beans"); + } + + brewingCoffee(): void { + console.log("Brewing coffee"); + } + + addingCondiments(): void { + console.log("Adding condiments"); + } +} +class Latte extends AbstractTemplate { + constructor() { + super("Latte"); + } + + grindingCoffeeBeans(): void { + console.log("Grinding coffee beans"); + } + + brewingCoffee(): void { + console.log("Brewing coffee"); + } + + addingCondiments(): void { + console.log("Adding milk"); + console.log("Adding condiments"); + } +} + +// @ts-ignore +entry(2, (...args) => { + args.forEach((type) => { + let coffee: AbstractTemplate; + if (type === 1) { + coffee = new AmericaCoffee(); + } else if (type === 2) { + coffee = new Latte(); + } else { + throw "type error"; + } + + coffee.templateMethod(); + }); +})(1)(2); diff --git a/js-advanced/design-pattern/behavioral/7.iterator.ts b/js-advanced/design-pattern/behavioral/7.iterator.ts new file mode 100644 index 0000000..e96db64 --- /dev/null +++ b/js-advanced/design-pattern/behavioral/7.iterator.ts @@ -0,0 +1,54 @@ +// 小明是一位老师,在进行班级点名时,希望有一个学生名单系统,请你实现迭代器模式提供一个迭代器使得可以按顺序遍历学生列表 + +import { entry } from "../utils"; + +interface IIterator { + hasNext(): boolean; + next(): T; +} + +interface IIterable { + createIterator(): IIterator; +} + +class NameList implements IIterator { + private idx: number; + private nameList: string[]; + + constructor(names: string[]) { + this.nameList = names; + this.idx = 0; + } + + hasNext(): boolean { + return this.idx < this.nameList.length; + } + + next(): string { + if (this.hasNext()) { + return this.nameList[this.idx++]; + } else { + throw "No more elements"; + } + } +} + +class ConcreteIterable implements IIterable { + private ele: string[]; + + constructor(ele: string[]) { + this.ele = ele; + } + + createIterator(): IIterator { + return new NameList(this.ele); + } +} + +// @ts-ignore +entry(3, (...args) => { + const iterator = new ConcreteIterable(args).createIterator(); + while (iterator.hasNext()) { + console.log(iterator.next()); + } +})("Alice 1001")("Bob 1002")("Charlie 1003"); diff --git a/js-advanced/design-pattern/behavioral/8.state/1.base.ts b/js-advanced/design-pattern/behavioral/8.state/1.base.ts new file mode 100644 index 0000000..8b5ad52 --- /dev/null +++ b/js-advanced/design-pattern/behavioral/8.state/1.base.ts @@ -0,0 +1,57 @@ +// 小明家有一个灯泡,刚开始为关闭状态(OffState)。 +// 台灯可以接收一系列的指令,包括打开("ON")、关闭("OFF")和闪烁("blink")。每次接收到一个指令后,台灯会执行相应的操作,并输出当前灯泡的状态。请设计一个程序模拟这个灯泡系统。 + +import { entry } from "../../utils"; + +interface IState { + handle(); +} + +class OnState implements IState { + handle() { + console.log("Light is ON"); + } +} + +class OffState implements IState { + handle() { + console.log("Light is OFF"); + } +} + +class BlinkState implements IState { + handle() { + console.log("Light is Blinking"); + } +} + +class StateContext { + private currentState: IState; + + constructor(state) { + this.currentState = state; + } + + setState(state: IState) { + this.currentState = state; + } + + getHandle() { + return this.currentState.handle(); + } +} + +// @ts-ignore +entry(5, (...args) => { + const classMap = { + ON: OnState, + OFF: OffState, + BLINK: BlinkState, + }; + + let state = new StateContext(new OffState()); + args.forEach((item) => { + state.setState(new classMap[item]()); + state.getHandle(); + }); +})("ON")("OFF")("BLINK")("OFF")("ON"); \ No newline at end of file diff --git a/js-advanced/design-pattern/behavioral/8.state/2.state copy.ts b/js-advanced/design-pattern/behavioral/8.state/2.state copy.ts new file mode 100644 index 0000000..dfe861c --- /dev/null +++ b/js-advanced/design-pattern/behavioral/8.state/2.state copy.ts @@ -0,0 +1,99 @@ +// 小明家有一个灯泡,刚开始为关闭状态(OffState)。 +// 台灯可以接收一系列的指令,包括打开("ON")、关闭("OFF")和闪烁("blink")。每次接收到一个指令后,台灯会执行相应的操作,并输出当前灯泡的状态。请设计一个程序模拟这个灯泡系统。 + +import { entry } from "../../utils"; + +interface IState { + turnOn(): OnState | null; + turnOff(): OffState | null; + turnBlink(): BlinkState | null; +} + +class OnState implements IState { + // 可以关、闪烁 + + turnOn() { + console.log("当前已经是打开状态"); + return null; + } + + turnOff(): OffState { + console.log("Light is ON"); + return new OffState(); + } + turnBlink(): BlinkState { + console.log("Light is Blinking"); + return new BlinkState(); + } +} + +class OffState implements IState { + // 可以开 + + turnOn() { + console.log("Light is ON"); + return new OnState(); + } + + turnOff() { + console.log("当前已经是关闭状态"); + return null; + } + + turnBlink() { + console.log("Light is Blinking"); + return new BlinkState(); + } +} + +class BlinkState implements IState { + // 可以关 + turnOn() { + console.log("当前已经是打开状态"); + return null; + } + + turnOff() { + console.log("Light is OFF"); + return new OffState(); + } + turnBlink() { + console.log("当前已经是闪烁状态"); + return null; + } +} + +class StateContext { + private currentState: IState; + + constructor(state) { + this.currentState = state; + } + + setState(state: IState) { + this.currentState = state; + } + + getHandle() { + return this.currentState; + } +} + +// @ts-ignore +entry(5, (...args) => { + const fnMap = { + ON: "turnOn", + OFF: "turnOff", + BLINK: "turnBlink", + }; + + let state = new StateContext(new OffState()); + args.forEach((item) => { + const handle = state.getHandle(); + const method = fnMap[item]; + const next = handle[method](); + if (next) { + state.setState(next); + } + }); +})("ON")("OFF")("BLINK")("OFF")("ON"); diff --git a/js-advanced/design-pattern/behavioral/8.state/3.work-state.ts b/js-advanced/design-pattern/behavioral/8.state/3.work-state.ts new file mode 100644 index 0000000..18b08f5 --- /dev/null +++ b/js-advanced/design-pattern/behavioral/8.state/3.work-state.ts @@ -0,0 +1,118 @@ +// 一个人不同时间,会有不同的工作状态 + +// < 12 上午工作,精神百倍 +// < 13 饿了,午饭; 犯困,午休 +// < 17 下午状态不错,继续努力 +// < 21 加班,疲累之极 +// + +interface IState { + // (method) IState.handle(workContent: WorkContent): void (+1 overload) + writeProgram(workContent: WorkContent): void; +} + +class MonWork implements IState { + writeProgram(workContent: WorkContent): void { + if (workContent.hour > 12) { + workContent.setState(new MiddleWork()); + workContent.request(); + } else { + console.log(`当前时间:${workContent.hour}。 上午工作,精神百倍`); + } + } +} + +class MiddleWork implements IState { + writeProgram(workContent: WorkContent): void { + if (workContent.hour > 13) { + workContent.setState(new AfterWork()); + workContent.request(); + } else { + console.log(`当前时间:${workContent.hour}。 饿了,午饭; 犯困,午休`); + } + } +} + +class AfterWork implements IState { + writeProgram(workContent: WorkContent): void { + if (workContent.hour > 17) { + if(workContent.workFinished) { + workContent.setState(new RestState()); + }else { + workContent.setState(new NightWork()); + } + workContent.request(); + } else { + console.log(`当前时间:${workContent.hour}。 下午状态不错,继续努力`); + } + } +} + +class NightWork implements IState { + writeProgram(workContent: WorkContent): void { + console.log(`当前时间:${workContent.hour}。 加班,疲累之极`); + } +} + +class RestState implements IState { + writeProgram(workContent: WorkContent): void { + console.log(`当前时间:${workContent.hour}。 下班回家`); + } +} + +class WorkContent { + private _hour: number = 0; + + public get hour(): number { + return this._hour; + } + public set hour(value: number) { + this._hour = value; + } + + private _workFinished = false; + public get workFinished() { + return this._workFinished; + } + + public set workFinished(value) { + this._workFinished = value; + } + + private state: IState; + + constructor(state: IState) { + this.state = state; + } + + setState(state: IState) { + this.state = state; + } + + request() { + this.state.writeProgram(this); + } +} + +const work = new WorkContent(new MonWork()); + +work.hour = 9; +work.request(); +work.hour = 10; +work.request(); +work.hour = 12; +work.request(); +work.hour = 13; +work.request(); +work.hour = 14; +work.request(); +work.hour = 17; +work.request(); +work.workFinished = true +// work.workFinished = false; +work.hour = 19; +work.request(); +work.hour = 22; +work.request(); + +export {}; diff --git a/js-advanced/design-pattern/behavioral/8.state/4.bank.ts b/js-advanced/design-pattern/behavioral/8.state/4.bank.ts new file mode 100644 index 0000000..c926a39 --- /dev/null +++ b/js-advanced/design-pattern/behavioral/8.state/4.bank.ts @@ -0,0 +1,58 @@ +// 如果账户中余额大于或等于0,则账户的状态为正常状态(Normal State)​,此时用户既可以向该账户存款也可以从该账户取款 +// 如果账户中余额小于0,并且大于-2000,则账户的状态为透支状态(Overdraft State)​,此时用户既可以向该账户存款也可以从该账户取款,但需要按天计算利息 +// 如果账户中余额等于-2000,那么账户的状态为受限状态(Restricted State)​,此时用户只能向该账户存款,不能再从中取款,同时也将按天计算利息。 +// 根据余额的不同,以上3种状态可发生相互转换 + +interface IState { + // 取款 + withdraw(bank: Bank, amount: number); + // 存款 + deposit(bank: Bank, amount: number); +} + +class NormalState implements IState { + withdraw(bank: Bank, amount: number) { + bank.amount -= amount; + } + + deposit(bank: Bank, amount: number) { + bank.amount += amount; + } +} +class OverdraftState implements IState { + withdraw(bank: Bank, amount: number) { + bank.amount -= amount; + } + + deposit(bank: Bank, amount: number) { + bank.amount += amount; + } +} +class RestrictedState implements IState { + withdraw(bank: Bank, amount: number) { + bank.amount -= amount; + } + + deposit(bank: Bank, amount: number) { + bank.amount += amount; + } +} + +class Bank { + amount: number = 0; + private state: IState; + + constructor(state: IState) { + this.state = state; + } + + take(amount: number) { + this.state.withdraw(this, amount); + } + + put(amount: number) { + this.state.deposit(this, amount); + } +} + +export {}; diff --git a/js-advanced/design-pattern/behavioral/9.chain-of-responsibility.ts b/js-advanced/design-pattern/behavioral/9.chain-of-responsibility.ts new file mode 100644 index 0000000..f6a4e8e --- /dev/null +++ b/js-advanced/design-pattern/behavioral/9.chain-of-responsibility.ts @@ -0,0 +1,79 @@ +// 小明所在的公司请假需要在OA系统上发布申请,整个请求流程包括多个处理者,每个处理者负责处理不同范围的请假天数,如果一个处理者不能处理请求,就会将请求传递给下一个处理者,请你实现责任链模式,可以根据请求天数找到对应的处理者。 + +import { entry } from "../utils"; + +// 审批责任链由主管(Supervisor), 经理(Manager)和董事(Director)组成,他们分别能够处理3天、7天和10天的请假天数。如果超过10天,则进行否决。 + +interface IHandler { + handleRequest(request: LeaveRequest): void; +} + +class Supervisor implements IHandler { + private nextHandler: IHandler; + constructor(handler: IHandler) { + this.nextHandler = handler; + } + + handleRequest(request: LeaveRequest): void { + if (request.getDays() > 3) { + // manage.setNext(new Manager()); + this.nextHandler.handleRequest(request); + } else { + console.log(`${request.getName()} Approved by Supervisor`); + } + } +} + +class Manager implements IHandler { + private nextHandler: IHandler; + constructor(handler: IHandler) { + this.nextHandler = handler; + } + + handleRequest(request: LeaveRequest): void { + if (request.getDays() > 7) { + this.nextHandler.handleRequest(request); + } else { + console.log(`${request.getName()} Approved by Manager`); + } + } +} + +class Director implements IHandler { + handleRequest(request: LeaveRequest): void { + if (request.getDays() > 10) { + console.log(`${request.getName()} Denied by Director`); + } else { + console.log(`${request.getName()} Approved by Director`); + } + } +} + +class LeaveRequest { + private name: string; + private days: number; + + constructor([name, days]) { + this.name = name; + this.days = days; + } + + getName() { + return this.name; + } + + getDays() { + return this.days; + } +} + +// @ts-ignore +entry(4, (...args) => { + const director = new Director(); + const manager = new Manager(director); + const supervisor = new Supervisor(manager); + args.forEach((info) => { + const request = new LeaveRequest(info); + supervisor.handleRequest(request); + }); +})(["Alice", 2])(["Bob", 5])(["Tom", 10])(["Jerry", 12]); diff --git a/js-advanced/design-pattern/01-singleton-hunger.ts b/js-advanced/design-pattern/create/01-singleton-hunger.ts similarity index 100% rename from js-advanced/design-pattern/01-singleton-hunger.ts rename to js-advanced/design-pattern/create/01-singleton-hunger.ts diff --git a/js-advanced/design-pattern/01-singleton-lazy.ts b/js-advanced/design-pattern/create/01-singleton-lazy.ts similarity index 100% rename from js-advanced/design-pattern/01-singleton-lazy.ts rename to js-advanced/design-pattern/create/01-singleton-lazy.ts diff --git a/js-advanced/design-pattern/create/02-easy-factory.ts b/js-advanced/design-pattern/create/02-easy-factory.ts new file mode 100644 index 0000000..cd01bb5 --- /dev/null +++ b/js-advanced/design-pattern/create/02-easy-factory.ts @@ -0,0 +1,47 @@ +// 小明家有两个工厂,一个用于生产圆形积木,一个用于生产方形积木, +// 请你帮他设计一个积木工厂系统,记录积木生产的信息。 + +// 简单工厂模式 通过 if、else 判断,简化了客户端。但是如果要添加新产品,需要修改工厂类代码。 +type TName = "Circle" | "Square"; + +interface Block { + product(): void; +} + +class Circle implements Block { + product(): void { + console.log("Circle BLock"); + } +} + +class Square implements Block { + product(): void { + console.log("Square BLock"); + } +} + +class Factory { + blocks: Block[] = []; + add(type: TName, quantity: number) { + const block = type === "Circle" ? Circle : Square; + for (let i = 0; i < quantity; i++) { + this.blocks.push(new block()); + } + } + + output() { + this.blocks.forEach((block) => { + block.product(); + }); + } +} + +const blockFactory = new Factory(); + +blockFactory.add("Circle", 1); +blockFactory.add("Square", 2); +blockFactory.add("Circle", 1); + +blockFactory.output(); + +export {}; diff --git a/js-advanced/design-pattern/create/02-factory.ts b/js-advanced/design-pattern/create/02-factory.ts new file mode 100644 index 0000000..d797aef --- /dev/null +++ b/js-advanced/design-pattern/create/02-factory.ts @@ -0,0 +1,60 @@ +// 小明家有两个工厂,一个用于生产圆形积木,一个用于生产方形积木, +// 请你帮他设计一个积木工厂系统,记录积木生产的信息。 + +interface IBlock { + product(): void; +} + +interface IFactory { + createBlock(): IBlock; +} + +class Circle implements IBlock { + product(): void { + console.log("Circle BLock"); + } +} + +class Square implements IBlock { + product(): void { + console.log("Square BLock"); + } +} + +class CircleFactory implements IFactory { + createBlock(): IBlock { + return new Circle(); + } +} + +class SquareFactory implements IFactory { + createBlock(): IBlock { + return new Square(); + } +} + +function main(count: number) { + function dfs(...args: [string, number][]) { + if (args.length < count) { + return (arg) => dfs(...args, arg); + } + + args.forEach((blockAndCount) => { + const factory = + blockAndCount[0] === "Circle" + ? new CircleFactory() + : new SquareFactory(); + + for (let i = 0; i < blockAndCount[1]; i++) { + factory.createBlock().product(); + } + }); + } + + return dfs; +} + +// @ts-ignore +main(3)(["Circle", 1])(["Square", 2])(["Circle", 1]); + +export {}; diff --git a/js-advanced/design-pattern/create/03.abstract-factory.ts b/js-advanced/design-pattern/create/03.abstract-factory.ts new file mode 100644 index 0000000..0205c63 --- /dev/null +++ b/js-advanced/design-pattern/create/03.abstract-factory.ts @@ -0,0 +1,82 @@ +// 小明家新开了两个工厂用来生产家具, +// 一个生产现代风格的沙发和椅子, +// 一个生产古典风格的沙发和椅子,现在工厂收到了一笔订单,请你帮他设计一个系统,描述订单需要生产家具的信息。 + +type TType = "classical" | "modern"; + +interface IChair { + productChair(); +} +interface ISofa { + productSofa(); +} + +interface IFactory { + createSofa(): ISofa; + createChair(): IChair; +} + +class ModernSofa implements ISofa { + productSofa() { + console.log("modern sofa"); + } +} + +class ModernChair implements IChair { + productChair() { + console.log("modern chair"); + } +} + +class ClassicalSofa implements ISofa { + productSofa() { + console.log("classical sofa"); + } +} + +class ClassicalChair implements IChair { + productChair() { + console.log("classical chair"); + } +} + +class ModernFactory implements IFactory { + createChair(): IChair { + return new ModernChair(); + } + createSofa(): ISofa { + return new ModernSofa(); + } +} + +class ClassicalFactory implements IFactory { + createChair(): IChair { + return new ClassicalChair(); + } + createSofa(): ISofa { + return new ClassicalSofa(); + } +} + +function main(count: number) { + const classicalFactory = new ClassicalFactory(); + const modernFactory = new ModernFactory(); + + function dfs(...args: TType[]) { + if (args.length === count) { + args.forEach((type) => { + const facotry = type === "classical" ? classicalFactory : modernFactory; + facotry.createChair().productChair(); + facotry.createSofa().productSofa(); + }); + } else { + return (arg) => dfs(...args, arg); + } + } + return dfs; +} + +// @ts-ignore +main(3)("modern")("classical")("modern"); + +export {} diff --git a/js-advanced/design-pattern/create/04-builder.ts b/js-advanced/design-pattern/create/04-builder.ts new file mode 100644 index 0000000..8d35aba --- /dev/null +++ b/js-advanced/design-pattern/create/04-builder.ts @@ -0,0 +1,80 @@ +// 小明家新开了一家自行车工厂,用于使用自行车配件(车架 frame 和车轮 tires )进行组装定制不同的自行车,包括山地车和公路车。 + +// 山地车使用的是Aluminum Frame(铝制车架)和 Knobby Tires(可抓地轮胎),公路车使用的是 Carbon Frame (碳车架)和 Slim Tries。 + +// 现在它收到了一笔订单,要求定制一批自行车,请你使用【建造者模式】告诉小明这笔订单需要使用那些自行车配置吧。 + +class Bicycle { + private frame = ""; + private tires = ""; + + setFrame(frame) { + this.frame = frame; + } + setTires(tires) { + this.tires = tires; + } + + toString() { + return this.frame + " " + this.tires; + } +} + +interface IBuilder { + buildFrame(): void; + buildTires(): void; + getResult(): Bicycle; +} + +class MountainBikeBuilder implements IBuilder { + private bicycle = new Bicycle(); + buildFrame(): void { + this.bicycle.setFrame("Aluminum Frame"); + } + + buildTires(): void { + this.bicycle.setTires("Knobby Tires"); + } + + getResult(): Bicycle { + return this.bicycle; + } +} +class RoadBikeBuilder implements IBuilder { + private bicycle = new Bicycle(); + buildFrame(): void { + this.bicycle.setFrame("Carbon Frame"); + } + + buildTires(): void { + this.bicycle.setTires("Slim Tries"); + } + + getResult(): Bicycle { + return this.bicycle; + } +} + +function main(count: number) { + function dfs(...args) { + if (args.length < count) { + return (...arg) => dfs(...args, ...arg); + } + + // todo + + args.forEach((bike) => { + const builder = + bike === "mountain" ? new MountainBikeBuilder() : new RoadBikeBuilder(); + builder.buildFrame(); + builder.buildTires(); + console.log(builder.getResult().toString()); + }); + } + return dfs; +} + +// @ts-ignore +main(3)("mountain")("road")("mountain"); + +export {}; diff --git a/js-advanced/design-pattern/create/05-prototype.ts b/js-advanced/design-pattern/create/05-prototype.ts new file mode 100644 index 0000000..9a2115e --- /dev/null +++ b/js-advanced/design-pattern/create/05-prototype.ts @@ -0,0 +1,43 @@ +// 公司正在开发一个图形设计软件,其中有一个常用的图形元素是矩形。 +// 设计师在工作时可能需要频繁地创建相似的矩形,而这些矩形的基本属性是相同的(颜色、宽度、高度), +// 为了提高设计师的工作效率,请你使用原型模式设计一个矩形对象的原型。使用该原型可以快速克隆生成新的矩形对象。 + +interface Prototype { + getDetail(): string; + clone(): Prototype; +} + +class Rectangle implements Prototype { + color: string; + width: number; + height: number; + + constructor(color: string, width: number, height: number) { + this.color = color; + this.width = width; + this.height = height; + } + + // 按实际需要实现 深拷贝或浅拷贝 + clone(): Rectangle { + return new Rectangle(this.color, this.width, this.height); + } + + getDetail(): string { + return `color: ${this.color}, width: ${this.width}, height: ${this.height}`; + } +} + +function main(color: string, width: number, height: number) { + const rectangle = new Rectangle(color, width, height); + + return function cpNumber(count: number) { + for (let i = 0; i < count; i++) { + console.log(rectangle.clone().getDetail()); + } + }; +} + +main("Red", 10, 5)(3); + +export {} \ No newline at end of file diff --git a/js-advanced/design-pattern/structural/01.adapter.ts b/js-advanced/design-pattern/structural/01.adapter.ts new file mode 100644 index 0000000..237b1db --- /dev/null +++ b/js-advanced/design-pattern/structural/01.adapter.ts @@ -0,0 +1,55 @@ +// 小明购买了一台新电脑,该电脑使用 TypeC 接口, +// 他已经有了一个USB接口的充电器和数据线,为了确保新电脑可以使用现有的USB接口充电器和数据线,他购买了一个TypeC到USB的扩展坞。 +// 请你使用适配器模式设计并实现这个扩展坞系统,确保小明的新电脑既可以通过扩展坞使用现有的USB接口充电线和数据线,也可以使用TypeC接口充电。 + +interface IUSB { + usbCharge(): void; +} + +interface ITypeC { + typeCCharge(): void; +} + +class USB implements IUSB { + usbCharge(): void {} +} + +// 适配器类,TypeC 扩展坞适配 USB +class TypeCAdapter implements IUSB, ITypeC { + private usb: IUSB; + + constructor(usb: IUSB) { + this.usb = usb; + } + + usbCharge() { + console.log("USB Adapter"); + this.usb.usbCharge(); + } + + typeCCharge(): void { + console.log("TypeC"); + this.usb.usbCharge(); + } +} + +function main(count: number) { + const expand = new TypeCAdapter(new USB()); + + function dfs(...args) { + if (args.length < count) return (...arg) => dfs(...args, ...arg); + + args.forEach((item) => { + if (item === 1) { + expand.typeCCharge(); + } else { + expand.usbCharge(); + } + }); + } + + return dfs; +} + +// @ts-ignore +main(3)(1)(2)(1); diff --git a/js-advanced/design-pattern/structural/02.proxy.ts b/js-advanced/design-pattern/structural/02.proxy.ts new file mode 100644 index 0000000..e318f38 --- /dev/null +++ b/js-advanced/design-pattern/structural/02.proxy.ts @@ -0,0 +1,34 @@ +// 小明想要购买一套房子,他决定寻求一家房屋中介来帮助他找到一个面积超过100平方米的房子, +// 只有符合条件的房子才会被传递给小明查看。 +import { entry } from "../utils"; + +interface IHouse { + sail(area: number): void; +} + +class RealHouse implements IHouse { + sail() { + console.log("Yes"); + } +} + +class MProxy implements IHouse { + private realHouse = new RealHouse(); + + sail(area: number) { + if (area < 100) { + console.log("NO"); + return; + } + + this.realHouse.sail(); + } +} + +// @ts-ignore +entry(3, (...args) => { + const proxy = new MProxy(); + args.forEach((item) => { + proxy.sail(item); + }); +})(120)(80)(110); diff --git a/js-advanced/design-pattern/structural/03.bridge.ts b/js-advanced/design-pattern/structural/03.bridge.ts new file mode 100644 index 0000000..3d36c8d --- /dev/null +++ b/js-advanced/design-pattern/structural/03.bridge.ts @@ -0,0 +1,89 @@ +// 小明家有一个万能遥控器,能够支持多个品牌的电视。每个电视可以执行开机、关机和切换频道的操作,请你使用桥接模式模拟这个操作。 + +import { entry } from "../utils"; + +// 0 表示创建 Sony 品牌的电视,1 表示创建 TCL 品牌的遥控和电视;2 表示开启电视、3表示关闭电视,4表示切换频道。 + +// Implementor +interface ITV { + turnOn(): void; + turnOff(): void; + changeChannel(): void; +} + +// ConcreteImplementor +class SonyTV implements ITV { + turnOn() { + console.log(`Sony TV is ON`); + } + turnOff() { + console.log(`Sony TV is OFF`); + } + changeChannel() { + console.log(`Switching Sony TV channel`); + } +} + +class TCL_TV implements ITV { + turnOn() { + console.log(`TCL TV is ON`); + } + turnOff() { + console.log(`TCL TV is OFF`); + } + changeChannel() { + console.log(`Switching TCL TV channel`); + } +} + +// Abstraction 维护一个对实现的引用 +abstract class Control { + protected tv: ITV; + constructor(tv: ITV) { + this.tv = tv; + } + + abstract operation(): void; +} + +// 修正抽象 RefinedAbstraction +class PowerOperation extends Control { + operation(): void { + this.tv.turnOn(); + } +} + +class OffOperation extends Control { + operation(): void { + this.tv.turnOff(); + } +} + +class ChannelSwitchOperation extends Control { + operation(): void { + this.tv.changeChannel(); + } +} + +// @ts-ignore +entry(6, (...args) => { + let tv: ITV; + args.forEach((item) => { + tv = item[0] === 0 ? new SonyTV() : new TCL_TV(); + + const action = item[1]; + switch (action) { + case 2: + new PowerOperation(tv).operation(); + break; + case 3: + new OffOperation(tv).operation(); + break; + case 4: + new ChannelSwitchOperation(tv).operation(); + break; + default: + console.log("invalid action"); + } + }); +})([0, 2])([1, 2])([0, 4])([0, 3])([1, 4])([1, 3]); diff --git a/js-advanced/design-pattern/structural/04.decorator.ts b/js-advanced/design-pattern/structural/04.decorator.ts new file mode 100644 index 0000000..5a1e198 --- /dev/null +++ b/js-advanced/design-pattern/structural/04.decorator.ts @@ -0,0 +1,61 @@ +// 小明喜欢品尝不同口味的咖啡,他发现每种咖啡都可以加入不同的调料,比如牛奶、糖和巧克力。他决定使用装饰者模式制作自己喜欢的咖啡。 +// 请设计一个简单的咖啡制作系统,使用装饰者模式为咖啡添加不同的调料。系统支持两种咖啡类型:黑咖啡(Black Coffee)和拿铁(Latte)。 + +import { entry } from "../utils"; + +interface ICoffee { + cOperation(): void; +} + +interface IDecorator { + dOperation(): void; +} + +class BlackCoffee implements ICoffee { + cOperation(): void { + console.log("Black Coffee"); + } +} + +class LatteCoffee implements ICoffee { + cOperation(): void { + console.log("Latte"); + } +} + +abstract class Decorator implements ICoffee { + protected coffee: ICoffee; + constructor(coffee: ICoffee) { + this.coffee = coffee; + } + + cOperation(): void { + this.coffee.cOperation(); + } +} + +class MilkCoffee extends Decorator { + dOperation(): void { + super.cOperation(); + console.log("adding Milk"); + } +} + +class SugarCoffee extends Decorator { + dOperation(): void { + super.cOperation(); + console.log("adding Sugar"); + } +} + +// @ts-ignore +entry(2, (...args) => { + let coffee: ICoffee; + let decorator: IDecorator; + + args.forEach((item) => { + coffee = item[0] === 1 ? new BlackCoffee() : new LatteCoffee(); + decorator = item[1] === 1 ? new MilkCoffee(coffee) : new SugarCoffee(coffee); + decorator.dOperation(); + }); +})([1, 1])([2, 2]); diff --git a/js-advanced/design-pattern/structural/05.facade.ts b/js-advanced/design-pattern/structural/05.facade.ts new file mode 100644 index 0000000..fee9e9c --- /dev/null +++ b/js-advanced/design-pattern/structural/05.facade.ts @@ -0,0 +1,56 @@ +// 小明家的电源总开关控制了家里的三个设备:空调、台灯和电视机。 +// 每个设备都有独立的开关密码,分别用数字1、2和3表示。即输入1时,空调关闭,输入2时,台灯关闭,输入3时,电视机关闭,当输入为4时,表示要关闭所有设备。 +// 请你使用外观模式编写程序来描述电源总开关的操作。 + +import { entry } from "../utils"; + +class AirCondition { + turnOff() { + console.log("Air Conditioner is turned off."); + } +} + +class DeskLamp { + turnOff() { + console.log("Desk Lamp is turned off."); + } +} + +class Television { + turnOff() { + console.log("Television is turned off."); + } +} + +class DeviceFacade { + private airCondition = new AirCondition(); + private deskLamp = new DeskLamp(); + private television = new Television(); + + turnOff(count: number) { + switch (count) { + case 1: + this.airCondition.turnOff(); + break; + case 2: + this.deskLamp.turnOff(); + break; + case 3: + this.television.turnOff(); + break; + case 4: + console.log("All devices are off."); + break; + default: + console.log("Invalid device code"); + } + } +} + +// @ts-ignore +entry(4, (...args) => { + const deviceFacade = new DeviceFacade(); + args.forEach((item) => { + deviceFacade.turnOff(item); + }); +})(1)(2)(3)(4); diff --git a/js-advanced/design-pattern/structural/06.compose.ts b/js-advanced/design-pattern/structural/06.compose.ts new file mode 100644 index 0000000..3f3424b --- /dev/null +++ b/js-advanced/design-pattern/structural/06.compose.ts @@ -0,0 +1,86 @@ +// 小明所在的公司内部有多个部门,每个部门下可能有不同的子部门或者员工。 +// 请你设计一个组合模式来管理这些部门和员工,实现对公司组织结构的统一操作。部门和员工都具有一个通用的接口,可以获取他们的名称以及展示公司组织结构。 + +import { entry } from "../utils"; + +// 每行描述一个部门或员工的信息。部门的信息格式为 D 部门名称,员工的信息格式为 E 员工名称,其中 D 或 E 表示部门或员工。 + +interface IComponent { + name: string; + display(dept: number): void; +} + +class Employer implements IComponent { + name: string; + + constructor(name: string) { + this.name = name; + } + + display(dept: number): void { + const indent = " ".repeat(dept * 4); + console.log(`${indent} ${this.name}`); + } +} + +class Department implements IComponent { + name: string; + private _children: IComponent[]; + + constructor(name: string) { + this.name = name; + this._children = []; + } + + add(child: IComponent) { + this._children.push(child); + } + + remove(child: IComponent) { + this._children = this._children.filter((item) => item.name !== child.name); + } + + display(dept: number): void { + const indent = " ".repeat(dept * 4); + console.log(`${indent} ${this.name}`); + + this._children.forEach((child) => { + child.display(dept + 1); + }); + } +} + +class Company { + private _department: Department; + + constructor(name: string) { + this._department = new Department(name); + } + + add(dept: Department) { + this._department.add(dept); + } + + display() { + this._department.display(1); + } +} + +// @ts-ignore +entry(8, (...args) => { + const company = new Company("MyCompany"); + let dept: Department; + args.forEach((item) => { + if (item[0] === "D") { + dept = new Department(item[1]); + company.add(dept); + } else { + dept.add(new Employer(item[1])); + } + }); + + company.display(); +})(["D", "HR"])(["E", "HRManager"])(["D", "Finance"])(["E", "AccountantA"])([ + "E", + "AccountantB", +])(["D", "IT"])(["E", "DeveloperA"])(["E", "DeveloperB"]); diff --git a/js-advanced/design-pattern/structural/07.flyWeight.ts b/js-advanced/design-pattern/structural/07.flyWeight.ts new file mode 100644 index 0000000..8923ea2 --- /dev/null +++ b/js-advanced/design-pattern/structural/07.flyWeight.ts @@ -0,0 +1,66 @@ +// 在一个图形编辑器中,用户可以绘制不同类型的图形,包括圆形(CIRCLE)、矩形(RECTANGLE)、三角形(TRIANGLE)等。现在,请你实现一个图形绘制程序,要求能够共享相同类型的图形对象,以减少内存占用。 + +import { entry } from "../utils"; + +interface TPos { + x: number; + y: number; +} + +type TShapeName = "CIRCLE" | "RECTANGLE" | "TRIANGLE"; + +interface IShape { + draw(pos: TPos): void; +} + +class CIRCLE implements IShape { + draw({ x, y }: TPos): void { + console.log(`(${x}, ${y})`); + } +} +class RECTANGLE implements IShape { + draw({ x, y }: TPos): void { + console.log(`(${x}, ${y})`); + } +} +class TRIANGLE implements IShape { + draw({ x, y }: TPos): void { + console.log(`(${x}, ${y})`); + } +} + +class GEditor { + shapeMap = new Map(); + + getShape(name: TShapeName) { + let shape: IShape; + if (!this.shapeMap.has(name)) { + switch (name) { + case "CIRCLE": + shape = new CIRCLE(); + break; + case "RECTANGLE": + shape = new RECTANGLE(); + break; + case "TRIANGLE": + shape = new TRIANGLE(); + break; + } + console.log(`${name} drawn at `); + this.shapeMap.set(name, shape); + } else { + console.log(`${name} shared at `); + shape = this.shapeMap.get(name)!; + } + return shape; + } +} + + +// @ts-ignore +entry(6, (...args) => { + const editor = new GEditor(); + args.forEach(([name, x, y]) => { + editor.getShape(name).draw({ x, y }); + }); +})(['CIRCLE', 10, 20])(['RECTANGLE', 30, 40])(['CIRCLE', 15, 25])(['TRIANGLE', 5, 15])(['CIRCLE', 10, 20])(['RECTANGLE', 30, 40]); diff --git a/js-advanced/design-pattern/utils.ts b/js-advanced/design-pattern/utils.ts new file mode 100644 index 0000000..be10520 --- /dev/null +++ b/js-advanced/design-pattern/utils.ts @@ -0,0 +1,10 @@ +export function entry(count: number, fn: (...args: any) => void) { + function dfs(...args) { + if (args.length < count) { + return (arg) => dfs(...args, arg); + } + + return fn(...args); + } + return dfs; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1c4e4f8 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,109 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": false, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +}