Angular 9 — Свойство ‘subscribe’ не существует для типа ‘void’

#angular #angular9

#angular #angular9

Вопрос:

Я получаю следующую ошибку:

Свойство ‘subscribe’ не существует для типа ‘void’.ts(2339)

когда я пытаюсь использовать свою функцию автоматического размещения (ниже), подписавшись на нее таким образом:

 this.AutoLocate().subscribe(data => { this.GotLoc = data});
  

Ниже приведена функция автоматического определения местоположения, а также функция getAddress, которую я использую для получения полной модели, использующей широту / длину и адрес.

   AutoLocate() {
    let AutoLocatedLocation: PlaceLocation;
    if(!Capacitor.isPluginAvailable('Geolocation')) {
      this.Alert.create({header: 'Location Service Error', message: 'Could not initialize Location Services! Please call support!'})
      return;
    }
    Plugins.Geolocation.getCurrentPosition().then(GeoPosition => {
      return this.coordinates = {lat: GeoPosition.coords.latitude, lng: GeoPosition.coords.longitude};
    }).then(coords => {
      this.GetAddress(coords.lat, coords.lng).subscribe(res => {
        this.Address = res;
        return AutoLocatedLocation = { lat: coords.lat, lng: coords.lng, address: res};
      });
    }).catch(error => {
      this.Alert.create({header: 'Location Service Error', message: 'Could not initialize Location Services! Please call support!'})
      console.log("Location: ", error);
    });
  }

  private GetAddress(lat: number, lng: number) {
    return this.http.get<any>(`https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}amp;key=${environment.googleMapsAPIKey}`)
    .pipe(map(geoData => {
      if (!geoData || !geoData.results || geoData.results.length === 0) {
        return null;
      }
      return geoData.results[0].formatted_address;
    }));
  }
  
  

Что я делаю не так?

Комментарии:

1. this.AutoLocate() не возвращает наблюдаемое значение, отсюда и сообщение об ошибке.

Ответ №1:

Похоже, вы смешиваете обещания с наблюдаемыми. Более AutoLocate() того, в данный момент функция ничего не возвращает.

Вы можете либо преобразовать observable в promise, либо наоборот. Я бы сделал первое, используя from функцию RxJS. Затем вы можете применить необходимые операторы для преобразования данных

 import { of, from, NEVER } from 'rxjs';
import { catchError, map, switchMap } from 'rxjs/operators';

AutoLocate(): Observable<any> {     // <-- return type `Observable`
  let AutoLocatedLocation: PlaceLocation;
  if(!Capacitor.isPluginAvailable('Geolocation')) {
    this.Alert.create({header: 'Location Service Error', message: 'Could not initialize Location Services! Please call support!'})
    return NEVER;       // <-- use RxJS `NEVER` constant - it'll never emit
  }
  
  return from(Plugins.Geolocation.getCurrentPosition()).pipe(  // <-- return the observable
    switchMap(GeoPosition => {
      const coords = { lat: GeoPosition.coords.latitude, lng: GeoPosition.coords.longitude };
      this.coordinates = coords;  // <-- why is this needed though?
      return this.GetAddress(coords.lat, coords.lng).pipe(
        map(res => {
          this.Address = res;     // <-- again, is this needed here?
          return ({ ...coords, address: res });  // spread operator `...` retains old values while adding/modifying other values
        })
      )
    }),
    catchError(error => {
      this.Alert.create({header: 'Location Service Error', message: 'Could not initialize Location Services! Please call support!'});
      return of(error);           // <-- `catchError` must return an observable
    })
  );
}
  

Разбивка:

  1. from функция для преобразования обещания в наблюдаемое
  2. NEVER константа, чтобы не отправлять подписку вместо простого JS return;
  3. map оператор для преобразования эмиссии в требуемый формат
  4. switchMap оператор для сопоставления одного наблюдаемого с другим
  5. catchError оператор для перехвата и запуска предупреждения. Обратите внимание, что это catchError должно возвращать наблюдаемое. of для этой функции используется функция.

Комментарии:

1. Мне, очевидно, нужно изучить наблюдаемые и обещания — я все еще очень новичок. Можете ли вы опубликовать одну или две ссылки, которые я должен прочитать, чтобы лучше учиться?

2. Почти работает! Однако я получаю сообщение об ошибке: (параметр) координаты: {широта: число; lng: число; } Аргумент типа ‘(координаты: {широта: число; lng: число; }) => void’ не может быть присвоен параметру типа ‘(значение: { широта: число; lng: number; }, index: number) => ObservableInput<любой>’. Тип ‘void’ не может быть присвоен типу ‘ObservableInput<any>’.ts(2345)

3. Нужно найти много ресурсов. Вот мои субъективные рекомендации для RxJS learnrxjs.io и обещает web.dev/promises

4. Ошибка, скорее всего, означает, что вам не хватает круглых скобок вокруг объекта внутри map оператора. Я отредактировал map оператор, чтобы было более понятно, как возвращается объект.

5. Говоря о том, что вам на самом деле не нужен map оператор здесь. Преобразование объекта может быть выполнено внутри switchMap . Я отредактировал ответ, чтобы удалить map . Пожалуйста, посмотрите, работает ли изменение.