类型“Observable<IProduct[]>”上不存在属性“do”。

49

升级到Angular 6.0和Rxjs 6.0之后,我收到以下编译错误:

属性“do”在类型“Observable”上不存在。

这是代码:

import { Observable, of } from 'rxjs';
import 'rxjs/add/operator/do';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/catch';
import { IProduct } from './product';

@Injectable()
export class ProductService { 
    constructor(
        private product: IProduct)
    {         
    }

    getProduct = () => { 
        return product.products
            // error on next line
            .do(data => console.log('All:' + JSON.stringify(data)))
            .catch(this.handleError);
    }

    private handleError(err: HttpErrorResponse) { 
        console.log(err.message);
        return Observable.throw(err.message);        
    }
}

有什么想法吗?


你能分享一个最简代码示例来说明问题吗?这将有助于我们调试出现的问题! - poundifdef
5
import { tap } from "rxjs/operators"; try like this `return next.handle(clonedReq).pipe(tap((err: any) => { }));` - Isanka Thalagala
5个回答

108
问题不在于 Angular,而在于 rxjs。rxjs 从版本 6 开始引入了破坏性变化。 为了让您的代码重新正常工作,而又无需更改任何代码,请安装以下软件包: npm install rxjs-compat@6 --save 然后,您就能编译您的项目了。rxjs-compat 是一个临时解决方案,因此您需要更新您的代码库以适应新版本。 新的导入路径: 您需要更新以下内容: 1.更新从导入语句 import { Observable } from "rxjs/Observable"; 到 import { Observable } from "rxjs"; 2.将您的操作符导入更新为 import 'rxjs/add/operator/do' 到 import { do } from "rxjs/operators"; 一些操作符也已由于与 JavaScript 保留字命名冲突而被重命名。 它们是: 1. do => tap 2. catch => catchError 3. switch => switchAll 4. finally => finalize 还有,您也不能再链接操作符了,您需要使用 pipe 运算符,例如:
// an operator chain
source
  .map(x => x + x)
  .mergeMap(n => of(n + 1, n + 2)
    .filter(x => x % 1 == 0)
    .scan((acc, x) => acc + x, 0)
  )
  .catch(err => of('error found'))
  .subscribe(printResult);
// must be updated to a pipe flow
source.pipe(
  map(x => x + x),
  mergeMap(n => of(n + 1, n + 2).pipe(
    filter(x => x % 1 == 0),
    scan((acc, x) => acc + x, 0),
  )),
  catchError(err => of('error found')),
).subscribe(printResult);

4
+1 表示支持详细说明已重命名的操作符。我注意到了名称空间和管道的更改,但错过了名称的更改。 - Vok
14
更新:import {tap} from 'rxjs/internal/operators';翻译:引入 rxjs/internal/operators 中的 tap 操作符。 - Augie Gardner
1
@TjaartvanderWalt 关于命名方面,我认为它不再是“Observable”类的属性。相反,它应该在pipe方法的第一个内联方法中作为方法调用。来源:https://stackoverflow.com/questions/50885262/replacing-the-share-function-for-in-rxjs6 - Mario
18
因此,.do() 变成了 .pipe(tap()) - user230910
1
'npm install rxjs-compat@6 --save' 对我解决了这个错误,并且对于 Angular CLI 7.2.1 (rxjs 6.3.3) 也是必需的。 - J E Carter II
显示剩余2条评论

20

我感谢Tjaart van der Walt关于如何解决Angular/rxjs7++中引入的“破坏性更改”的回复。但是,我仍然在尝试将他的回复应用到我的Angular拦截器时遇到了几个问题:

以下是更新后的代码(未能编译的部分标记为“OLD”)

import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpResponse} from '@angular/common/http';
import {HttpHandler, HttpRequest, HttpErrorResponse} from '@angular/common/http';

/*
  OLD:
  import {Observable} from 'rxjs/Observable';
  import 'rxjs/add/operator/do';
 */
import { Observable } from 'rxjs';
import { of } from 'rxjs';
import { tap, catchError } from 'rxjs/operators';

import { AuthService } from './auth.service';

@Injectable()
export class StockAppInterceptor implements HttpInterceptor {

  constructor(private authService: AuthService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (this.authService.authToken) {
      const authReq = req.clone({
        headers: req.headers.set(
          'Authorization',
          this.authService.authToken
        )
      });
      console.log('Making an authorized request');
      req = authReq;
    }
    /*
     * OLD:
     * return next.handle(req)
     *   .do(event => this.handleResponse(req, event),
     *      error => this.handleError(req, error));
     */
    return next.handle(req).pipe(
      tap(
        event => this.handleResponse(req, event),
        error => this.handleError(req, error)
      )
    );
  }


  handleResponse(req: HttpRequest<any>, event) {
    console.log('Handling response for ', req.url, event);
    if (event instanceof HttpResponse) {
      console.log('Request for ', req.url,
          ' Response Status ', event.status,
          ' With body ', event.body);
    }
  }

  handleError(req: HttpRequest<any>, event) {
    console.error('Request for ', req.url,
          ' Response Status ', event.status,
          ' With error ', event.error);
  }
}

需要进行的更改包括更改import路径,以及将pipe()tap()of()替换为新的方法。

这个链接也是RxJS6变化的一个很好的资源:

https://www.academind.com/learn/javascript/rxjs-6-what-changed/


1
我正在创建一个拦截器,这个答案对我帮助很大。谢谢。 - phpfresher

15

Rxjs 6引入了一些重大更改,“do”操作符已被“tap”操作符所取代(来自'rxjs/internal/operators')。

您可以使用新的操作符重新构建代码,或者通过添加rxjs-compat库以实现向后兼容性仍然使用旧的“do”语法(npm install --save rxjs-compat)。

请注意,在RxJs 6之前,您需要导入“do”操作符:

import 'rxjs/add/operator/do';

更多细节请参见:Angular HTTP GET与TypeScript出现错误:http.get(...).map在[null]中不是一个函数


已经导入了,请参考我附带的代码快照来解决问题! - Urgen
如上所述,这对于rxjs 6.0或更高版本是不正确的。 您需要从rxjs/operators导入tap并更改语法。 或者导入rxjs-compat@6(如果无法避免更新代码,则为“最后的手段”)。 - paulsm4

6
“do” 操作符在 rxjs 6 中已被替换为“tap”操作符,因此出现了以下错误:“属性“do”在类型“Observable<IProduct[]>”上不存在”。
要解决此错误,您有两个选项: 解决方案1:修补你的代码...它将可与“do”操作符正常工作。
npm install rxjs-compat@6 --save

解决方案2: 用以下代码替换你的next.handle代码
 return next.handle(req).pipe(
      tap(
        event => this.handleResponse(req, event),
        error => this.handleError(req, error)
      )
    );

1

只需在您的TypeScript文件中使用:

import 'rxjs/add/operator/do';

就是这么简单。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接