Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion tscconfig/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
12 changes: 12 additions & 0 deletions tscconfig/src/base/declare/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// 在实际项目中,通常不会在 .ts 文件中直接使用 declare,而是将这些类型声明写在**类型定义文件(.d.ts)**中。

// 只声明,不定义
// declare 不会生成任何实际的 JavaScript 代码,它只在类型系统中生效。如果你想要实际的实现,请不要使用 declare。

// 编译后不会输出任何代码

declare var API_URL: string;
declare function fetchData(url: string): Promise<any>;

// declare 和 .d.ts 文件的关系
// .d.ts 文件是专门存储声明的文件,通常用于为第三方库定义类型文件
24 changes: 24 additions & 0 deletions tscconfig/src/base/declare/index.ts
Original file line number Diff line number Diff line change
@@ -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");
1 change: 1 addition & 0 deletions tscconfig/src/base/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "./namespace";
28 changes: 28 additions & 0 deletions tscconfig/src/base/namespace.ts
Original file line number Diff line number Diff line change
@@ -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);
16 changes: 16 additions & 0 deletions tscconfig/src/decorators/01-class-decorator/index.ts
Original file line number Diff line number Diff line change
@@ -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);
}
24 changes: 24 additions & 0 deletions tscconfig/src/decorators/01-class-decorator/second.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
function reportableClassDecorator<T extends { new (...args: any[]): {} }>(
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 {}
29 changes: 29 additions & 0 deletions tscconfig/src/decorators/02-method-decorator/first.ts
Original file line number Diff line number Diff line change
@@ -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 {};
2 changes: 2 additions & 0 deletions tscconfig/src/decorators/02-method-decorator/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import "./first";
import "./second";
29 changes: 29 additions & 0 deletions tscconfig/src/decorators/02-method-decorator/second.ts
Original file line number Diff line number Diff line change
@@ -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 {};
30 changes: 30 additions & 0 deletions tscconfig/src/decorators/03-accessor-decorator/first.ts
Original file line number Diff line number Diff line change
@@ -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 {};
1 change: 1 addition & 0 deletions tscconfig/src/decorators/03-accessor-decorator/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "./first";
14 changes: 14 additions & 0 deletions tscconfig/src/decorators/04-property/first.ts
Original file line number Diff line number Diff line change
@@ -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 {};
1 change: 1 addition & 0 deletions tscconfig/src/decorators/04-property/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "./first";
7 changes: 7 additions & 0 deletions tscconfig/src/decorators/README.md
Original file line number Diff line number Diff line change
@@ -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)
3 changes: 3 additions & 0 deletions tscconfig/src/decorators/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import "./01-class-decorator";
import "./02-method-decorator";
import "./03-accessor-decorator";
18 changes: 18 additions & 0 deletions tscconfig/src/decorators/reflect-metadata/README.md
Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import "reflect-metadata";

type Constructor<T = any> = 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 = <T>(target: Constructor<T>): 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

Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import "reflect-metadata";

type Constructor<T = any> = 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<T>(value: string) {
return function (target: Constructor<T>) {
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)
Loading