Класс машинописного текста Typeof не может быть назначен классу, который его расширяет.

У нас есть базовый класс StoreObject, который предоставляет общие методы преобразования/лечения и т. д. для объектов, сохраняемых в БД. Я хотел бы иметь возможность указывать более строгие типы возврата из этих методов с помощью дженериков. Однако мои попытки приводят к ошибкам при сравнении typeof StoreObject с typeof AClassThatExtendsStoreObject, проверка, которую мы делаем в различных служебных функциях. Можете ли вы указать мне направление того, что я делаю неправильно ниже?


class StoreObject<S> {
  toStoreObject(s: S): S {
    // Perform some sanitisation etc.
    return s;
  }
}

interface Fact {
  id: string;
  fact: string;
}

// A concrete implementation of StoreUnit where we attempt to define the actual model of the object being stored
class FactStoreObject extends StoreObject<Fact> {}

// We've got some general utils that interact objects using these classes 
// These typicallay take a concrete implementation of StoreUnit to be used as a parser/processer
function doSomething(StoreObjectClass: typeof StoreObject) {
  // Typically:
  // const parsedObject = new StoreObjectClass(someObject).toStoreObject()
  // persistToDb(parsedObject)
}

// This errors with "Type 'S' is not assignable to type 'Fact'"
doSomething(FactStoreObject);

playground link


person Henry Munro    schedule 08.07.2019    source источник
comment
Вы не можете сделать doSomething() общим? FactStoreObject не может создавать общие экземпляры StoreObject<S>... он может создавать только экземпляры StoreObject<Fact>.   -  person jcalz    schedule 08.07.2019


Ответы (2)


В предоставленном коде в функции doSomething тип параметра указывается как StoreObject без общего типа, который он просматривает. Чтобы исправить ошибку, вам нужно сделать что-то вроде:

  1. Передайте общий параметр для StoreObject (в данном случае Fact) в doSomthing.

  2. Параметр функции doSomething должен указывать тип с сигнатурой конструктора, который позволяет создать новый экземпляр.

    Вот образец:

function doSomething<T>(StoreObjectClass: { new(): StoreObject<T> }) {
  // typically
  const someObject = <any>{id: "001", fact: "A real fact"};
  const parsedObject = new StoreObjectClass().toStoreObject(someObject);
  // persistToDb(parsedObject)
}

doSomething<Fact>(FactStoreObject);
person Luis    schedule 08.07.2019

Ошибка связана с этой строкой:

const parsedObject = new StoreObjectClass(someObject)

Во-первых, вам нужен конструируемый интерфейс:

export interface IConstructable<T> {
    new (): T;
}

Во-вторых, вам нужно включить параметр типа в ваш фабричный метод:

function doSomething<T>( t: IConstructable<T> ) {
  const parsedObject = ( new t() ).toStoreObject();
  // persistToDb(parsedObject);
}
person Riad Baghbanli    schedule 08.07.2019
comment
Несмотря на то, что мы оба пришли к одному и тому же решению, я хотел бы признать, что использование интерфейса для подписи конструктора было элегантным штрихом. - person Luis; 12.07.2019