如何在TypeScript中每次调用静态类方法时都调用静态方法



我创建了一个singleton(抽象(类,在使用大多数方法之前,该类需要初始化一些数据。这是一个类的外观示例:

abstract class MyClass {
private static initialize(): void {
// do stuff
}
public static doStuff1(param1: string): string {
MyClass.initialize();
// do stuff
return 'stuff1';
}
public static doStuff2(param2: string[]): string[] {
MyClass.initialize();
// do stuff
return ['stuff2'];
}
}

有没有办法避免在每个方法上添加这些initialize()调用?我考虑过使用decorator,发现了一个相关的问题:Typescript |每次调用函数时都调用函数

不幸的是,它使用的是遗留的decorator格式,至少这是我得到的错误:

Syntax error - Support for the experimental syntax 'decorators-legacy' isn't currently enabled

我试图使用第二阶段的提案找到一个等效的格式,但也许有更好的选择?

(通常不鼓励单身汉,但由于我不知道你的用例,我认为你有充分的理由使用他们,不会考虑其他选择(

为了解决您的问题,您可以使用一个小的包装器实用程序来装饰您的函数:

const wrap = <T extends (...args: any[]) => any>(func: T): T =>
<T>((...args: any[]) => {
// Do something before every function here...
return func(...args);
});

然后你可以这样定义你的函数:

abstract class MyClass {
public static doStuff1 = wrap((param1: string): string => {
// do stuff
return 'stuff1';
});
}

现在保证函数doStuff1在执行自己的代码之前始终执行wrap中的代码。

这种方法的问题在于,您无法访问MyClass的私有状态或函数,这可能是可取的。您可以在每次包装方法时传递对该方法的引用,但这样做并不比在每个函数的开头调用它好多少。

更好的方法:非静态单例

如果您无论如何都在使用singleton,那么最好以非静态的方式实现它,并保证一次性免费初始化:

class MyClass {
private static instance?: MyClass;
static getInstance = (): MyClass =>
(MyClass.instance = MyClass.instance ?? new MyClass());
private constructor() {
// Do your initialization
console.log("initializing");
}
doStuff1() {
// do stuff
console.log("doing stuff 1");
}
doStuff2() {
// do stuff
console.log("doing stuff 2");
}
}
MyClass.getInstance().doStuff1();
// Output:
// initializing
// doing stuff 1
MyClass.getInstance().doStuff1();
MyClass.getInstance().doStuff2();
// Output:
// doing stuff 1
// doing stuff 2

请注意,从上面的输出中,初始化只调用一次,这(根据您的问题判断(似乎是所需的行为

我同意soimons的回答,因为它鼓励更干净的代码。尽管如此,您可能会使用代理对象来包装抽象类,这样您的调用就感觉像是在使用静态单例。

我不确定这是否有副作用,但它似乎满足了你的需要。

_MyClass.ts

abstract class _MyClass {
private static count:number = 0;
private static initialize(): void {
console.log('initialized'+_MyClass.count++);
}
private static doStuff1(param1: string): string {
return 'stuff1';
}
private static doStuff2(param2: string[]): string[] {
return ['stuff2'];
}
public static handler2 = {
get: function(target:any, prop:Function) {
_MyClass.initialize();
return Reflect.get(target,prop);
}
};
}
const MyClass = new Proxy(_MyClass, _MyClass.handler2);
export {MyClass};

指数.ts

import { MyClass } from "./_MyClass"
alert(MyClass.doStuff1())

上述代码将生成以下内容:

[LOG]: "initialized0" 
[LOG]: "stuff1" 
[LOG]: "initialized1" 
[LOG]: ["stuff2"] 

如果这对任何人都有帮助,我最终选择了一条简单得多的路线,基本上是导出一个非静态类的实例。因此,它不再是一个真正的单例,这意味着没有什么可以阻止更多实例的初始化,但这样做(除了测试(真的没有意义

class MyClass {
private prop1: string[];
private prop2: string;
constructor(): {
// load data into the object
this.prop1 = ['a', 'b'];
this.prop2 = 'c';
}
public getProp1(param: string[]): string[] {
return this.prop1;
}
public getProp2(param: string): string {
return this.prop2;
}
}
const myClass = new MyClass();
export default myClass;

最新更新