泛型类部分初始化器

时间:2018-08-21 09:45:14

标签: typescript object-initializers

我想使用以下语法初始化很多类似的类:

class A {
    b: number = 1
    constructor(initializer?: Partial<A>) {
        Object.assign(this, initializer)
    }
}

new A({b: 2})

我认为能够通过这种方式进行初始化是一种常规行为,因此我想隔离这种逻辑,以避免在文件的重复中重复自己。我尝试过:

class Initializable<T> {
    constructor(initializer?: Partial<T>) {
        Object.assign(this, initializer)
    }
}

class A extends Initializable<A> {
    b: number = 1
}

new A({b: 2})

这可以编译,但是不起作用,因为隐式super()首先进入,所以b根据需要得到2,然后得到1

TypeScript是否提供类型安全的解决方案来在我所有的类中实现此行为?

1 个答案:

答案 0 :(得分:1)

在派生类构造函数完成之后,没有简单的方法可以从基类中运行某些操作。我能看到的唯一解决方案(并且我邀请其他人提出一个更好的解决方案:))是使用一个增加了将成为A类的函数,而不是使用基类。基本上是添加功能的mixin方法。

function initializable<T extends new() => any>(cls: T) : {
    new (data?: Partial<InstanceType<T>>) : InstanceType<T> // add the constructor
} & Pick<T, keyof T> /* add statics back */ {
    return class extends (cls as any) {
        constructor(data?: Partial<InstanceType<T>>){
            super();
            if(data) { 
                Object.assign(this, data);
            }
        }
    } as any

}

const A = initializable(class {
    b: number = 2;
    static staticMethod() { }
    method() {}
});
type A = InstanceType<typeof A> // Optionally define the type for A to have the same effect as the class

var a = new A({b:1});
console.log(a.b) // output 1
a.method();
A.staticMethod();
a = new A();
console.log(a.b) // output 2
var aErr = new A({b:"1"}); //error

注意通常不允许混入不更改构造函数参数,这就是为什么我们必须稍微按摩一下类型但可以解决问题的原因。