Как внедрить условные проверки перед выполнением любых методов класса - PullRequest
0 голосов
/ 26 марта 2019

Я ищу некоторые мнения / решения о том, как изящно обрабатывать асинхронный поиск данных.

При асинхронной инициализации любого класса с некоторыми данными я использовал такой подход:

class SomeClass {
  // Turning off ts compiler's strictPropertyInitialization
  private someProperty: SomeType 

  public async init(): Promise<this> {
    this.someProperty = await goAndGetDataFromWhoKnowsWhere();
    return this;
  }

  public async aMethod(): Promise<AType> {
    // do its thing
  }

  public async anotherMethod(): Promise<AnotherType> {
    // do its thing
  }
}

И ожидайте, что пользователь (я / другой сотрудник) будет использовать этот класс следующим образом:

const someResult = new SomeClass()
  .init()
  .then( thatClass => thatClass.aMethod() )

Этот подход, безусловно, подходит для этой цели, но нет никаких жестких ограничений, чтобы гарантировать, что init() вызывается. Иногда, когда кто-то забывает об этом, вещи ломаются

Возможно, мы могли бы включить strictPropertyInitialization и внедрить проверку в каждом методе класса. Это сработало бы наверняка, но идентичные строки в методах кричат, что, возможно, есть лучший способ.

class SomeClass {
  private someProperty: SomeType | undefined // To enforce null-checking

  public async init(): Promise<this> {
    this.someProperty = await goAndGetDataFromWhoKnowsWhere();
    return this;
  }

  public async aMethod(): Promise<AType> {
    if (!this.someProperty) await this.init();
    // do its thing
  }

  public async anotherMethod(): Promise<AnotherType> {
    if (!this.someProperty) await this.init();
    // do its thing
  }
}

Есть ли решения этой проблемы? Какие-либо шаблоны проектирования, которые работают вокруг этой проблемы? Помогает ценится! :)

Ответы [ 3 ]

1 голос
/ 26 марта 2019

Вы когда-нибудь думали о том, чтобы вообще не показывать вызов конструктора new()? Что если вы создадите конструктор private и предоставите статический метод init(), который асинхронно создает экземпляр и заполняет его данными:

class SomeClass {

  static async init(): Promise<SomeClass> {
    return new SomeClass(await goAndGetDataFromWhoKnowsWhere());
  }

  private constructor(private someProperty: SomeType) {  }

  // your other methods    
}


new SomeClass("oops"); // can't do this

SomeClass.init().then(thatClass => thatClass.aMethod());

Теперь никто не может использовать это неправильно. Надеюсь, что это дает вам некоторые идеи. Удачи!

0 голосов
/ 26 марта 2019

Как насчет использования функции вместо?

function SomeClass(){
  var newObj = Object.create(/* your prototype */)
  return goAndGetDataFromWhoKnowsWhere()
  .then((data) => {
    newObj.someProperty = data;
    return newObj;
  })
}

SomeClass().then((newObj) => {})
0 голосов
/ 26 марта 2019

Другой вариант - вы можете обернуть создание класса в функцию.Предполагая, что init должен вызываться в каждом экземпляре, вы можете просто обработать это при создании:

(Извините, это не в TypeScript; я просто не так знаком с ним.)

const goAndGetDataFromWhoKnowsWhere = async () => 123;

const SomeClass = () => {
  class SomeClass {
    async init() {
      this.someProperty = await goAndGetDataFromWhoKnowsWhere();
      return this;
    }
  }
  return new SomeClass().init();
};

SomeClass().then(inst => {
  console.log('someProperty:', inst.someProperty);
});

По аналогии с ответом jcalz это не позволяет использовать ключевое слово new:

new SomeClass(); // TypeError: SomeClass is not a constructor
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...