From 01ba5fb8d3ddd1820cd0af0c8c8789dbeca289bf Mon Sep 17 00:00:00 2001 From: caojunjie <1301239018@qq.com> Date: Thu, 12 Dec 2024 20:18:41 +0800 Subject: [PATCH 1/3] feat(decorator) --- tscconfig/package.json | 3 +- tscconfig/src/base/index.ts | 1 + tscconfig/src/base/namespace.ts | 28 +++++++++++++ .../decorators/01-class-decorator/index.ts | 16 ++++++++ .../decorators/01-class-decorator/second.ts | 24 +++++++++++ .../decorators/02-method-decorator/first.ts | 29 +++++++++++++ .../decorators/02-method-decorator/index.ts | 2 + .../decorators/02-method-decorator/second.ts | 29 +++++++++++++ .../decorators/03-accessor-decorator/first.ts | 30 ++++++++++++++ .../decorators/03-accessor-decorator/index.ts | 1 + tscconfig/src/decorators/04-property/first.ts | 14 +++++++ tscconfig/src/decorators/04-property/index.ts | 1 + tscconfig/src/decorators/index.ts | 3 ++ .../src/decorators/reflect-metadata/README.md | 18 ++++++++ .../src/decorators/reflect-metadata/first.ts | 41 +++++++++++++++++++ .../src/decorators/reflect-metadata/index.ts | 2 + tscconfig/src/index.ts | 2 + tscconfig/src/test/iife.js | 8 ++++ tscconfig/tsconfig.json | 4 +- tscconfig/yarn.lock | 5 +++ 20 files changed, 258 insertions(+), 3 deletions(-) create mode 100644 tscconfig/src/base/index.ts create mode 100644 tscconfig/src/base/namespace.ts create mode 100644 tscconfig/src/decorators/01-class-decorator/index.ts create mode 100644 tscconfig/src/decorators/01-class-decorator/second.ts create mode 100644 tscconfig/src/decorators/02-method-decorator/first.ts create mode 100644 tscconfig/src/decorators/02-method-decorator/index.ts create mode 100644 tscconfig/src/decorators/02-method-decorator/second.ts create mode 100644 tscconfig/src/decorators/03-accessor-decorator/first.ts create mode 100644 tscconfig/src/decorators/03-accessor-decorator/index.ts create mode 100644 tscconfig/src/decorators/04-property/first.ts create mode 100644 tscconfig/src/decorators/04-property/index.ts create mode 100644 tscconfig/src/decorators/index.ts create mode 100644 tscconfig/src/decorators/reflect-metadata/README.md create mode 100644 tscconfig/src/decorators/reflect-metadata/first.ts create mode 100644 tscconfig/src/decorators/reflect-metadata/index.ts create mode 100644 tscconfig/src/test/iife.js diff --git a/tscconfig/package.json b/tscconfig/package.json index 815dc5d..f8d2351 100644 --- a/tscconfig/package.json +++ b/tscconfig/package.json @@ -21,6 +21,7 @@ "@electron-toolkit/preload": "^3.0.1" }, "devDependencies": { - "@types/node": "17.0.16" + "@types/node": "17.0.16", + "reflect-metadata": "^0.2.2" } } diff --git a/tscconfig/src/base/index.ts b/tscconfig/src/base/index.ts new file mode 100644 index 0000000..2b44170 --- /dev/null +++ b/tscconfig/src/base/index.ts @@ -0,0 +1 @@ +import "./namespace"; \ No newline at end of file diff --git a/tscconfig/src/base/namespace.ts b/tscconfig/src/base/namespace.ts new file mode 100644 index 0000000..3e240dd --- /dev/null +++ b/tscconfig/src/base/namespace.ts @@ -0,0 +1,28 @@ +namespace Base { + declare const age: number; + + export const name = "base"; + + export function getName() { + return name; + } + + function getName3() { + return name2; + } + + export declare const name2: string; + export declare function getName2(): string; + + (function () { + const name2 = "name2"; + const getName2 = () => name2; + }); +} + + +(function (abc) { + console.log(abc); + const name2 = "name2"; + const getName2 = () => name2; +})(123); diff --git a/tscconfig/src/decorators/01-class-decorator/index.ts b/tscconfig/src/decorators/01-class-decorator/index.ts new file mode 100644 index 0000000..c0defca --- /dev/null +++ b/tscconfig/src/decorators/01-class-decorator/index.ts @@ -0,0 +1,16 @@ +import "./first"; + +@sealed +class BugReport { + type = "report"; + title: string; + + constructor(t: string) { + this.title = t; + } +} + +function sealed(constructor: Function) { + Object.seal(constructor); + Object.seal(constructor.prototype); +} diff --git a/tscconfig/src/decorators/01-class-decorator/second.ts b/tscconfig/src/decorators/01-class-decorator/second.ts new file mode 100644 index 0000000..1db6723 --- /dev/null +++ b/tscconfig/src/decorators/01-class-decorator/second.ts @@ -0,0 +1,24 @@ +function reportableClassDecorator( + constructor: T +) { + return class extends constructor { + reportingURL = "http://www..."; + }; +} + +@reportableClassDecorator +class BugReport { + type = "report"; + title: string; + + constructor(t: string) { + this.title = t; + } +} + +const bug = new BugReport("Needs dark mode"); +console.log(bug.title); // Prints "Needs dark mode" +console.log(bug.type); // Prints "report" +console.log(bug); + +export {} \ No newline at end of file diff --git a/tscconfig/src/decorators/02-method-decorator/first.ts b/tscconfig/src/decorators/02-method-decorator/first.ts new file mode 100644 index 0000000..8e038dd --- /dev/null +++ b/tscconfig/src/decorators/02-method-decorator/first.ts @@ -0,0 +1,29 @@ +class Greeter { + greeting: string; + constructor(message: string) { + this.greeting = message; + } + + @enumerable(true) + greet() { + return "Hello, " + this.greeting; + } +} + +function enumerable(value: boolean) { + return function ( + target: any, + propertyKey: string, + descriptor: PropertyDescriptor + ) { + descriptor.enumerable = value; + }; +} + +const greeter = new Greeter("world"); + +console.log("Object.keys(greeter)", Object.keys(greeter)); +console.log("Object.getOwnPropertyNames(greeter)", Object.getOwnPropertyNames(greeter)); +console.log("Object.getOwnPropertyDescriptors(greeter)", Object.getOwnPropertyDescriptors(greeter)); + +export {}; diff --git a/tscconfig/src/decorators/02-method-decorator/index.ts b/tscconfig/src/decorators/02-method-decorator/index.ts new file mode 100644 index 0000000..b14212a --- /dev/null +++ b/tscconfig/src/decorators/02-method-decorator/index.ts @@ -0,0 +1,2 @@ +import "./first"; +import "./second"; diff --git a/tscconfig/src/decorators/02-method-decorator/second.ts b/tscconfig/src/decorators/02-method-decorator/second.ts new file mode 100644 index 0000000..43616ae --- /dev/null +++ b/tscconfig/src/decorators/02-method-decorator/second.ts @@ -0,0 +1,29 @@ +function first() { + console.log("first(): factory evaluated"); + return function ( + target: any, + propertyKey: string, + descriptor: PropertyDescriptor + ) { + console.log("first(): called"); + }; +} + +function second() { + console.log("second(): factory evaluated"); + return function ( + target: any, + propertyKey: string, + descriptor: PropertyDescriptor + ) { + console.log("second(): called"); + }; +} + +class ExampleClass { + @first() + @second() + method() {} +} + +export {}; \ No newline at end of file diff --git a/tscconfig/src/decorators/03-accessor-decorator/first.ts b/tscconfig/src/decorators/03-accessor-decorator/first.ts new file mode 100644 index 0000000..8b9061d --- /dev/null +++ b/tscconfig/src/decorators/03-accessor-decorator/first.ts @@ -0,0 +1,30 @@ +class Point { + private _x: number; + private _y: number; + constructor(x: number, y: number) { + this._x = x; + this._y = y; + } + + @configurable(false) + get x() { + return this._x; + } + + @configurable(false) + get y() { + return this._y; + } +} + +function configurable(value: boolean) { + return function ( + target: any, + propertyKey: string, + descriptor: PropertyDescriptor + ) { + descriptor.configurable = value; + }; +} + +export {}; \ No newline at end of file diff --git a/tscconfig/src/decorators/03-accessor-decorator/index.ts b/tscconfig/src/decorators/03-accessor-decorator/index.ts new file mode 100644 index 0000000..d452daa --- /dev/null +++ b/tscconfig/src/decorators/03-accessor-decorator/index.ts @@ -0,0 +1 @@ +import "./first"; diff --git a/tscconfig/src/decorators/04-property/first.ts b/tscconfig/src/decorators/04-property/first.ts new file mode 100644 index 0000000..9e06a8f --- /dev/null +++ b/tscconfig/src/decorators/04-property/first.ts @@ -0,0 +1,14 @@ +// class Greeter { +// @format("Hello, %s") +// greeting: string; +// constructor(message: string) { +// this.greeting = message; +// } +// greet() { +// let formatString = getFormat(this, "greeting"); +// return formatString.replace("%s", this.greeting); +// } +// } + + +export {}; diff --git a/tscconfig/src/decorators/04-property/index.ts b/tscconfig/src/decorators/04-property/index.ts new file mode 100644 index 0000000..e9d68dd --- /dev/null +++ b/tscconfig/src/decorators/04-property/index.ts @@ -0,0 +1 @@ +import "./first"; \ No newline at end of file diff --git a/tscconfig/src/decorators/index.ts b/tscconfig/src/decorators/index.ts new file mode 100644 index 0000000..cea8569 --- /dev/null +++ b/tscconfig/src/decorators/index.ts @@ -0,0 +1,3 @@ +import "./01-class-decorator"; +import "./02-method-decorator"; +import "./03-accessor-decorator"; diff --git a/tscconfig/src/decorators/reflect-metadata/README.md b/tscconfig/src/decorators/reflect-metadata/README.md new file mode 100644 index 0000000..36150eb --- /dev/null +++ b/tscconfig/src/decorators/reflect-metadata/README.md @@ -0,0 +1,18 @@ +# IoC 和 DI + +## 控制反转 Inversion of Control (IoC) + +- 不是一种技术,是一种思想 +- 控制反转是一种设计原则,用于将对象的创建和依赖关系的管理从应用程序中分离出来,交给外部容器来管理 +- 控制反转的目的是为了降低耦合度,提高代码的可维护性和可测试性 +- 控制反转的实现方式有多种,比如依赖注入、依赖注入容器、依赖注入框架等 + +## 依赖注入 Dependency Injection (DI) + +- 依赖注入是一种设计模式,用于将对象的依赖关系从应用程序中分离出来,交给外部容器来管理 +- 依赖注入的目的是为了降低耦合度,提高代码的可维护性和可测试性 +- 依赖注入的实现方式有多种,比如依赖注入容器、依赖注入框架等 + +## 参考文档 + +[Reflect Metadata](https://jkchao.github.io/typescript-book-chinese/tips/metadata.html#%E5%9F%BA%E7%A1%80) diff --git a/tscconfig/src/decorators/reflect-metadata/first.ts b/tscconfig/src/decorators/reflect-metadata/first.ts new file mode 100644 index 0000000..acce4f2 --- /dev/null +++ b/tscconfig/src/decorators/reflect-metadata/first.ts @@ -0,0 +1,41 @@ +import "reflect-metadata"; + +// Reflect.metadata(key, value):这是一个装饰器工厂函数,用于将 元数据 (metadata) 附加到类、方法、属性或参数上。 +// Reflect.getMetadata(key, target):用于从目标对象(类、方法、属性或参数)中 获取元数据。 +// Reflect.metadata 使用 WeakMap 来存储元数据,确保不会影响垃圾回收(GC)和内存管理。 + +@Reflect.metadata("inClass", "A") +class Test { + @Reflect.metadata("inMethod", "B") + public hello(): string { + return "hello world"; + } +} + +// 上面的存储结构图 +const metadataStore = { + Test: { + inClass: "A", + prototype: { + hello: { + inMethod: "B", + }, + }, + }, +}; + +// 实现的核心逻辑 +function metadata(metadataKey: string, metadataValue: any) { + return function (target: any, propertyKey: string) { + if (!propertyKey) { + // 类装饰器 + Reflect.defineMetadata(metadataKey, metadataValue, target); + } else { + // 方法/属性装饰器 + Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey); + } + }; +} + +console.log(Reflect.getMetadata("inClass", Test)); // 'A' +console.log(Reflect.getMetadata("inMethod", new Test(), "hello")); // 'B' diff --git a/tscconfig/src/decorators/reflect-metadata/index.ts b/tscconfig/src/decorators/reflect-metadata/index.ts new file mode 100644 index 0000000..879cbf9 --- /dev/null +++ b/tscconfig/src/decorators/reflect-metadata/index.ts @@ -0,0 +1,2 @@ +import "./first"; +import "./dependency-injection"; diff --git a/tscconfig/src/index.ts b/tscconfig/src/index.ts index 02ffd5c..58e8fce 100644 --- a/tscconfig/src/index.ts +++ b/tscconfig/src/index.ts @@ -1,6 +1,8 @@ import constants from "@common/constants"; import { electronAPI } from "@electron-toolkit/preload"; import "./debug"; +import "./decorators"; +import "./base"; console.log(constants.CLOSE_INNER_WINDOW); diff --git a/tscconfig/src/test/iife.js b/tscconfig/src/test/iife.js new file mode 100644 index 0000000..32a3d1d --- /dev/null +++ b/tscconfig/src/test/iife.js @@ -0,0 +1,8 @@ +(function (fn) { + const name = "inner name"; // 定义一个局部变量 name + console.log("iife"); // 输出 "iife" + fn(name); // 调用传入的函数 fn,并将 name 作为参数传递 +})(function (inner) { + console.log("iife2"); // 输出 "iife2" + console.log("getInnerName", inner); // 输出传入的参数 inner +}); diff --git a/tscconfig/tsconfig.json b/tscconfig/tsconfig.json index ad63321..fb24e28 100644 --- a/tscconfig/tsconfig.json +++ b/tscconfig/tsconfig.json @@ -27,8 +27,8 @@ "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. */ + "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*'. */ diff --git a/tscconfig/yarn.lock b/tscconfig/yarn.lock index 2f97a26..694a246 100644 --- a/tscconfig/yarn.lock +++ b/tscconfig/yarn.lock @@ -11,3 +11,8 @@ version "17.0.16" resolved "https://registry.npmmirror.com/@types/node/-/node-17.0.16.tgz#e3733f46797b9df9e853ca9f719c8a6f7b84cd26" integrity sha512-ydLaGVfQOQ6hI1xK2A5nVh8bl0OGoIfYMxPWHqqYe9bTkWCfqiVvZoh2I/QF2sNSkZzZyROBoTefIEI+PB6iIA== + +reflect-metadata@^0.2.2: + version "0.2.2" + resolved "https://registry.npmmirror.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b" + integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== From a9e16b7bbfea103e4073acf3bba2efc47a75abf8 Mon Sep 17 00:00:00 2001 From: caojunjie <1301239018@qq.com> Date: Fri, 13 Dec 2024 19:36:07 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat(DI=E3=80=81IoC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tscconfig/src/base/declare/index.d.ts | 12 +++ tscconfig/src/base/declare/index.ts | 24 ++++++ .../dependency-injection/angular.ts | 32 ++++++++ .../dependency-injection/nest.ts | 80 +++++++++++++++++++ .../dependency-injection/person.js | 30 +++++++ .../src/decorators/reflect-metadata/first.ts | 5 ++ 6 files changed, 183 insertions(+) create mode 100644 tscconfig/src/base/declare/index.d.ts create mode 100644 tscconfig/src/base/declare/index.ts create mode 100644 tscconfig/src/decorators/reflect-metadata/dependency-injection/angular.ts create mode 100644 tscconfig/src/decorators/reflect-metadata/dependency-injection/nest.ts create mode 100644 tscconfig/src/decorators/reflect-metadata/dependency-injection/person.js diff --git a/tscconfig/src/base/declare/index.d.ts b/tscconfig/src/base/declare/index.d.ts new file mode 100644 index 0000000..af76af7 --- /dev/null +++ b/tscconfig/src/base/declare/index.d.ts @@ -0,0 +1,12 @@ +// 在实际项目中,通常不会在 .ts 文件中直接使用 declare,而是将这些类型声明写在**类型定义文件(.d.ts)**中。 + +// 只声明,不定义 +// declare 不会生成任何实际的 JavaScript 代码,它只在类型系统中生效。如果你想要实际的实现,请不要使用 declare。 + +// 编译后不会输出任何代码 + +declare var API_URL: string; +declare function fetchData(url: string): Promise; + +// declare 和 .d.ts 文件的关系 +// .d.ts 文件是专门存储声明的文件,通常用于为第三方库定义类型文件 \ No newline at end of file diff --git a/tscconfig/src/base/declare/index.ts b/tscconfig/src/base/declare/index.ts new file mode 100644 index 0000000..d4839e8 --- /dev/null +++ b/tscconfig/src/base/declare/index.ts @@ -0,0 +1,24 @@ +// declare 关键字用于声明但不定义变量、函数、类、枚举、命名空间或模块的类型。这是为了告诉 TypeScript 编译器:“这段代码的实现在其他地方,通常是外部的,比如 JavaScript 文件、全局环境、第三方库等。” + +// ===== 声明全局变量 +// 告诉 TypeScript:有一个名为 jQuery 的全局变量,类型是 any +declare var jQuery: any; + +// 使用 jQuery(不会报错) +jQuery("#app").addClass("active"); + +// ===== 声明全局函数 +declare function log(message: string): void; + +// 调用 log 函数(不会报错) +log("Hello World"); + +// ===== 声明一个全局的命名空间 +declare namespace MyNamespace { + export const version: string; + export function greet(name: string): void; +} + +// 使用 MyNamespace +console.log(MyNamespace.version); +MyNamespace.greet("Alice"); diff --git a/tscconfig/src/decorators/reflect-metadata/dependency-injection/angular.ts b/tscconfig/src/decorators/reflect-metadata/dependency-injection/angular.ts new file mode 100644 index 0000000..f3f70b2 --- /dev/null +++ b/tscconfig/src/decorators/reflect-metadata/dependency-injection/angular.ts @@ -0,0 +1,32 @@ +import "reflect-metadata"; + +type Constructor = new (...args: any[]) => T; + +const Good = (): ClassDecorator => target => {}; + +class OtherService { + a = 1; +} + +@Good() +class TestService { + constructor(public readonly otherService: OtherService) {} + + testMethod() { + console.log(this.otherService.a); + } +} + +const Factory = (target: Constructor): T => { + // 获取所有注入的服务 + const providers = Reflect.getMetadata("design:paramtypes", target); + if(providers) { + const args = providers.map((provider: any) => new provider); + return new target(...args); + } + + return new target(); +} + +Factory(TestService).testMethod(); // 1 + diff --git a/tscconfig/src/decorators/reflect-metadata/dependency-injection/nest.ts b/tscconfig/src/decorators/reflect-metadata/dependency-injection/nest.ts new file mode 100644 index 0000000..2e85694 --- /dev/null +++ b/tscconfig/src/decorators/reflect-metadata/dependency-injection/nest.ts @@ -0,0 +1,80 @@ +import "reflect-metadata"; + +type Constructor = new (...args: any[]) => T; + +const PATH_METADATA = "path"; +const METHOD_METADATA = "method"; +@Controller("/test") +class SomeClass { + @Get("/a") + someGetMethod() { + return "hello world"; + } + + @Post("/b") + somePostMethod() {} +} + +function Controller(value: string) { + return function (target: Constructor) { + Reflect.defineMetadata(PATH_METADATA, value, target); + }; +} + +function createMappingDecorator(method: string, path: string) { + return function ( + target: any, + propertyKey: string, + descriptor: PropertyDescriptor + ) { + Reflect.defineMetadata(PATH_METADATA, path, target, propertyKey); + Reflect.defineMetadata(METHOD_METADATA, method, target, propertyKey); + }; +} + +function Get(path: string) { + return createMappingDecorator("GET", path); +} + +function Post(path: string) { + return createMappingDecorator("POST", path); +} + +const routes = Reflect.getMetadata(PATH_METADATA, SomeClass); +const methods = Reflect.getMetadata(METHOD_METADATA, SomeClass); + +console.log(routes); +console.log(methods); + +function isConstructor(value: any) { + return typeof value === "function" && value.prototype !== undefined; +} + +function isFunction(value: any) { + return typeof value === "function"; +} + +function mapRoutes(instance: Object) { + const prototype = Object.getPrototypeOf(instance); + + const methodNames = Object.getOwnPropertyNames(prototype).filter( + (item) => isFunction(prototype[item]) && !isConstructor(prototype[item]) + ); + + return methodNames.map((methodName) => { + const fn = prototype[methodName]; + const route = Reflect.getMetadata(PATH_METADATA, instance, methodName); + const method = Reflect.getMetadata(METHOD_METADATA, instance, methodName); + + return { + route, + method, + methodName, + fn, + }; + }); +} + +console.log(mapRoutes(new SomeClass())); + +console.log(1) \ No newline at end of file diff --git a/tscconfig/src/decorators/reflect-metadata/dependency-injection/person.js b/tscconfig/src/decorators/reflect-metadata/dependency-injection/person.js new file mode 100644 index 0000000..11702aa --- /dev/null +++ b/tscconfig/src/decorators/reflect-metadata/dependency-injection/person.js @@ -0,0 +1,30 @@ +class Person { + name; + age; + + constructor(name, age) { + this.name = name; + this.age = age; + } + + getName() { + return this.name; + } + + getAge() { + return this.age; + } +} + +// Object.getPrototypeOf 获取的是参数的 __proto__ 属性 +console.log("getPrototypeOf 相关====="); +console.log(Object.getPrototypeOf(Person)); + +console.log(Object.getPrototypeOf(new Person('章三', 18))); + +console.log(Object.getOwnPropertyNames(Object.getPrototypeOf(new Person('章三', 18)))); + +console.log("getOwnPropertyNames 相关====="); +console.log(Object.getOwnPropertyNames(Person)); +console.log(Object.getOwnPropertyNames(Person.prototype)); + diff --git a/tscconfig/src/decorators/reflect-metadata/first.ts b/tscconfig/src/decorators/reflect-metadata/first.ts index acce4f2..787c03c 100644 --- a/tscconfig/src/decorators/reflect-metadata/first.ts +++ b/tscconfig/src/decorators/reflect-metadata/first.ts @@ -4,6 +4,8 @@ import "reflect-metadata"; // Reflect.getMetadata(key, target):用于从目标对象(类、方法、属性或参数)中 获取元数据。 // Reflect.metadata 使用 WeakMap 来存储元数据,确保不会影响垃圾回收(GC)和内存管理。 +console.log("first"); + @Reflect.metadata("inClass", "A") class Test { @Reflect.metadata("inMethod", "B") @@ -39,3 +41,6 @@ function metadata(metadataKey: string, metadataValue: any) { console.log(Reflect.getMetadata("inClass", Test)); // 'A' console.log(Reflect.getMetadata("inMethod", new Test(), "hello")); // 'B' + +const test = new Test(); +test.hello(); From 9f158ec4859196836bbef63b0dddbd82a00e3f89 Mon Sep 17 00:00:00 2001 From: caojunjie <1301239018@qq.com> Date: Wed, 18 Dec 2024 14:16:17 +0800 Subject: [PATCH 3/3] doc --- tscconfig/src/decorators/README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tscconfig/src/decorators/README.md diff --git a/tscconfig/src/decorators/README.md b/tscconfig/src/decorators/README.md new file mode 100644 index 0000000..4d74de9 --- /dev/null +++ b/tscconfig/src/decorators/README.md @@ -0,0 +1,7 @@ +# Decorators + +## 参考文档 + +[es6 装饰器](https://es6.ruanyifeng.com/#docs/decorator) +[ts-Decorators](https://www.typescriptlang.org/docs/handbook/decorators.html#metadata) +[深入理解 TypeScript](https://jkchao.github.io/typescript-book-chinese/tips/metadata.html#%E5%9F%BA%E7%A1%80)