为了使构造函数调用更具可读性,我通常更喜欢使用命名参数,如下所示:
class MyClass {
constructor(private args: {a: number, b: string, c: boolean}) {}
}
// Example constructor call:
const x = new MyClass({a: 1, b: "hello", c: true})
但是,我还希望 a
、b
和 c
是公开可读的,即我希望能够调用x.a
、x.b
和 x.c
而不是使用 x.args.a
、x.args.b
和 x.args.c
。我可以想出几种不同的方法来做到这一点(见下文),但它们都涉及重复的样板文件来显式创建属性或 getter。
有没有一种方法可以自动创建这些 setter/getter ,例如通过编写装饰器还是使用泛型?
方法 1:显式声明属性并在构造函数中填充它们
这太冗长了!
class MyClass1 {
a: number;
b: string;
c: boolean;
constructor(private args: {a: number, b: string, c: boolean}) {
this.a = args.a;
this.b = args.b;
this.c = args.c;
}
}
方法 2:存储参数并编写 getter
比方法 1 更简洁,但我希望自动创建这些 getter。
class MyClass2 {
constructor(private args: {a: number, b: string, c: boolean}) {};
get a(): number {return this.args.a}
get b(): string {return this.args.b}
get c(): boolean {return this.args.c}
}
最佳答案
这可以使用装饰器完成您想要的事情:
// Decorator setup
interface IndexedObject { [name: string]: any }
type Constructor = new(...args: any[]) => IndexedObject
function namedConstructorArgs <T extends Constructor> (targetConstructor: T): T {
return class proxyConstructor extends targetConstructor {
constructor(...args: any[]){
super(args)
Object.entries(args[0]).forEach(
eachNamedArg => this[ eachNamedArg[0] ] = eachNamedArg[1]
)
}
}
}
// In main program
abstract class MyClassLoggerProperties {
a: string
b: number
}
@namedConstructorArgs
class MyClassLogger extends MyClassLoggerProperties {
constructor(_: MyClassLoggerProperties) {
super()
}
log() {
console.log(this.a, this.b)
}
}
new MyClassLogger( { a: "i like flake number", b: 99 } )
.log() // logs: I like flake number, 99
注意,我必须关闭 strictPropertyInitialization
编译器标志,以便编译器接受未在其自己的构造函数中初始化的类的属性。如果您希望保留编译器标志,您还可以将属性初始化为虚拟值。
抽象类用于确保类声明中的类属性与构造函数中的类属性相同,否则编译器不会检查它们是否一致。您可以在这些地方重复属性声明并省略构造函数中的 super()
调用,但这不是类型安全的。
关于typescript:自动为构造函数的所有命名参数创建 getter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65446045/