首页 > 解决方案 > Reconstruct generic class with parameters in the constructor

问题描述

I am trying to create a class method that will reconstruct the class with given data.

For example,

class A {
   constructor (one, two) {...}

  public static from(data: A): A {
    return Object.assign(new A(), data);
  }
}

And then do something like:

let someObj = A.from({one: 'hello', two: 'world'}

This works fine. But now I want to make this method generic, to call it with any class.

I have tried

export function from<T>(type: { new (): T }, input: T): T {
  return Object.assign(new type(), input);
}

But the issue is that this wont work if the class needs arguments in the constructor.

How can I achieve that?

标签: typescript

解决方案


您可以使用Object.create指定的原型创建对象,而无需调用构造函数。通过将对象的原型设置为type.prototype,它将是类的一个实例type,因此它将具有该类定义的方法,就像调用new type().

function from<T>(type: { new(...args: any[]): T }, input: T): T {
    return Object.assign(Object.create(type.prototype), input);
}

必须说这明显违反了封装,所以你必须保证你只会用它来创建具有有效内部状态的对象。由于没有调用构造函数,因此对象没有机会验证自己的状态。

例子:

class A {
    constructor(public x: number) { }
    getX() { return this.x; }
}

var a = new A(1);
var b = from(A, a);
var c = from(A, { x: 4 }); // type error here, unfortunately.

console.log(b.getX()); // logs 1
console.log(c.getX()); // logs 4

不幸的是,类型注释input: T会导致编译器抱怨{ x: 4 }没有实例应该具有的getX属性。A我们可以通过构造一个排除方法的映射类型来解决这个问题:

type FieldsOf<T> = Pick<T, { [K in keyof T]: T[K] extends Function ? never : K }[keyof T]>;

function from<T>(type: { new(...args: any[]): T }, input: FieldsOf<T>): T {
    return Object.assign(Object.create(type.prototype), input);
}

游乐场链接


推荐阅读