Как создать DRY Angular код с наблюдаемыми типами? - PullRequest
1 голос
/ 29 апреля 2020

У меня проблема с количеством дублирующихся кодов как в моем компоненте, так и в классе обслуживания. Я хотел бы уменьшить это, где это возможно, сохранив при этом строгую типизацию. Есть ли способ уменьшить количество аналогичного кода, передавая интерфейс или что-то подобное?

Допустим, у нас есть 5 типов:

  • Дом
  • Человек
  • Животное
  • Завод
  • Автомобиль

Я определил все мои типы, где каждый тип отличается, кроме Первичного ключа (id) :

interface House {
  address: string;
  squareFt: number;
  id: string;
  ...
}

interface Person {
  name: string;
  age: number;
  id: string
  ...
}

У меня есть мой компонент: app.component.ts

export class AppComponent implements OnInit {
  house: House;
  person: Person;
  animal: Animal;
  plant: Plant;
  car: Car;

  constructor(public dataService: DataService){ }

  ngOnInit() {
    // House
    this.dataService.getHouseData().subscribe(
      (house: House) => {
        this.house = house;
        ...
      },
      (error) => console.error(error),
      () => console.log('Finished House Data')
    );

    // Person
    this.dataService.getPersonData().subscribe(
      (person: Person) => {
        this.person = person;
        ...
      },
      (error) => console.error(error),
      () => console.log('Finished Person Data')
    );

    ...
  }

У меня есть этот сервис: dataService.ts

export class DataService {
  constructor(public http: HttpClient) {}

  handleError(error: Response) {
    // handlesErrors
  }

  retryWithBackOff(delay, maxRetry) {
   // retry http call with exponential backoff
  }

  // Get House Data
  public getHouseData(): Observable<House> {
    return this.http.get<House>(myURL).pipe(
      this.retryWithBackoff(1000, 3),
      catchError(this.handleError)
    )
  }

  // Get Person Data
  public getPersonData(): Observable<Person> {
    return this.http.get<Person>(myURL).pipe(
      this.retryWithBackoff(1000, 3),
      catchError(this.handleError)
    )
  }
  ...
}

Что бы я хотел сделать что-то вроде этого, чтобы уменьшить мой код: app.component.ts

export class AppComponent implements OnInit {
  house: House;
  person: Person;
  animal: Animal;
  plant: Plant;
  car: Car;

  constructor(public dataService: DataService){ }

  ngOnInit() {
    const obj = [
      {
        url: 'house'
        type: House
      }, {
        url: 'person'
        type: Person
      },  
      ...
    ];

    _.map(obj, (val) => {
      this.dataService.getData<val.type>().subscribe(
        (data: val.type) => {
          if(val.url === 'house') this.house = data;
          if(val.url === 'person') this.person = data;
          ...
        },
        (error) => console.error(error),
        () => console.log('Finished retrieving data')
      );
    }    
  }

Затем: dataService.ts

export class DataService {
  constructor(public http: HttpClient) {}

  handleError(error: Response) {
    // handlesErrors
  }

  retryWithBackOff(delay, maxRetry) {
   // retry http call with exponential backoff
  }

  // Get Data
  public getData<T>(): Observable<t> {
    return this.http.get<T>(myURL).pipe(
      this.retryWithBackoff(1000, 3),
      catchError(this.handleError)
    )
  }
}

Возможно ли что-то подобное?

1 Ответ

1 голос
/ 29 апреля 2020

Итак, это просто другой подход, объединение ваших потоков помогает очистить код.

  ngOnInit() {
    forkJoin(
      this.dataService.getHouseData(),
      this.dataService.getPersonData()
    ).subscribe(
      ([house: House, person: Person]) => {
        this.house = house;
        this.person = person;
      },
      (error) => console.error(error),
      () => console.log('Finished Data')
    );
  }

, но даже лучше, вообще не подписывается и использует асин * c pipe:

  ngOnInit() {
    this.house$ = this.dataService.getHouseData()
    this.person$ = this.dataService.getPersonData()
  }

и в шаблонах вы можете использовать их следующим образом:

<div *ngIf="house$ | async as house">{{house | json}}</div>

<div *ngIf="person$ | async as person">{{person | json}}</div>

или даже комбинировать методы, если хотите:

  ngOnInit() {
    this.data$ = forkJoin({
      house: this.dataService.getHouseData(),
      person: this.dataService.getPersonData()
    })
  }

<div *ngIf="data$ | async as data">
  {{data.house | json}}
  {{data.person | json}}
</div>
...