Как определить generi c конструктор в машинописи при наследовании? - PullRequest
0 голосов
/ 16 января 2020

Я использую машинопись и хочу написать фабричную функцию для создания нового экземпляра объекта и предоставления массива свойств для заполнения. В основном преобразователь из существующего объекта в новый экземпляр другого (связанного) типа. Он должен использоваться следующим образом:

const newA = A.from({ a: 1 });
const newC = C.from({ a: 1, b: 2, c: 9 });

У меня это работает (переменные-члены для ясности опущены, и Object.create может быть проще, причина приведена ниже)

class A {
  static from(data: Partial<A>) : A {
    const o = Object.create(A);
    Object.assign(o, data);
    return o;
  }
}

Это работает хорошо, пока я наследую от этого класса. Я не хочу воссоздавать эту функцию в любое время, например

class A {
  static from(data: Partial<A>) : A {
    const o = Object.create(A);
    Object.assign(o, data);
    return o;
  }
}

class B extends A {
static from(data: Partial<B>) : B {
    const o = Object.create(B);
    Object.assign(o, data);
    return o;
  }
}

Следующий фрагмент кода работает, но мне нужно указать класс, когда я вызываю его дважды

class A {
  ...
  static from<T extends A>(data: Partial<T>) : T {
    const o = Object.create(this);
    Object.assign(o, data);
    return o;
  }
}

const newC = C.from<C>({ ... });

и хочу использовать некоторая форма generi c, т.е. я представляю что-то вроде этого.

class A {
  static from<T extends this>(data: Partial<T>) : A {
    const o = Object.create(this);
    Object.assign(o, data);
    return o;
  }
}

const new C = C.from({ ... });

Я бы предположил, что это теоретически возможно, так как во время компиляции контекст функции stati c известен, и вы мог бы вывести тип класса, но я не выяснил, как использовать этот унаследованный тип в определении сигнатуры.

Это хороший (приемлемый) шаблон, и если нет, то что мне делать?

Любая помощь приветствуется!

1 Ответ

2 голосов
/ 16 января 2020

Вы ищете polymorphi c this types для методов stati c, но в настоящее время они не поддерживаются в TypeScript. Для этого есть запрос на открытую функцию, microsoft / TypeScript # 5863 , но я не знаю, будет ли он когда-либо реализован.

К счастью, есть обходные пути, один из которых упоминается здесь : используйте метод generi c, в котором параметр this зависит от шаблона c. Например:

class A {
    static from<T extends A>(this: new () => T, data: Partial<T>): T {
        const o = new this(); // no-arg constructor
        Object.assign(o, data);
        return o;
    }
}

Здесь мы позволим вызывать from() только для объектов, которые не являются аргументами конструкторов некоторого подтипа A, и они будут возвращать этот подтип. Я изменил реализацию с Object.create(this) на new this() просто для того, чтобы показать, что нам небезразлично "отсутствие аргументов" (в конце концов, подкласс с Object.create(this), для которого требовался аргумент конструктора, скорее всего не сможет создать действительный экземпляр).

Итак, это работает, поскольку B является конструктором без аргументов B экземпляров:

class B extends A {
    foo = "bar";
}
const b = B.from({}); // B
console.log(b.foo.toUpperCase()); // BAR

, но это не удается, поскольку Z не конструктор без аргументов Z экземпляров:

class Z extends A {
    constructor(public bar: string) {
        super();
    }
}
const z = Z.from({}); // error!
// -----> ~
// typeof Z is not assignable to new () => Z
console.log(z.bar.toUpperCase());  // error at runtime, z.bar is undefined

Хорошо, надеюсь, это поможет; удачи!

Детская площадка ссылка на код

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...