泛型 class 部分初始值设定项

generic class partial initializer

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

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 是否提供类型安全的解决方案来在我的所有 类 中实现此行为?

没有简单的方法可以在派生的 class 构造函数完成后从基础 class 中 运行 一些东西。我能看到的唯一解决方案(我邀请其他人提出更好的解决方案 :) )是使用一个函数来增强将成为 A class 的函数,而不是使用基数 class.基本上是添加功能的混合方法。

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

注意 通常不允许混入不更改构造函数参数,这就是为什么我们必须对类型进行一些修改,但它确实有效。