"void"类型无法分配给"type 'ObservableInput<{}>'"

80
这个错误在我迁移到TS 2.2.2后开始出现,所以我认为这是问题的原因……代码没有停止工作,但现在我收到了这个错误,我尝试了一些事情,比如返回一个空的observable,捕获重新抛出的异常并返回一个对象,但似乎都不起作用。为什么现在会出现这种情况?它不应该理解我正在重新抛出异常而不期望返回值吗?我是否误读了错误信息?
这是完整的错误描述:

enter image description here

这是完整的代码:

return request
    .map((res: Response) => res.json())
    .catch((error: any) => {
        // todo: log?

        if (error.status == 500) {
            this.alertService.showError(error.statusText);
        } else if (error.status == 588) {
            this.alertService.showAlert(error.statusText);
        }

        Observable.throw(error.statusText);
    });

我尝试返回Observable,但我的包装方法期望返回类型为T,这是我的反序列化请求(map(...))的返回值。如果我确实返回throw,我会得到以下错误:
[ts] 类型“Observable”不能赋值给类型“T”
我正在使用:
Angular4
Typescript 2.2.2
5个回答

114

你需要返回这个Observable

 return request
    .map((res: Response) => res.json())
    .catch((error: any) => {
        // todo: log?

        if (error.status == 500) {
            this.alertService.showError(error.statusText);
        } else if (error.status == 588) {
            this.alertService.showAlert(error.statusText);
        }

        return Observable.throw(error.statusText);
    });

谢谢你的回答,我之前尝试过了。但是它不起作用,因为我的包装方法需要返回T类型。请检查我的更新问题。很抱歉我忘记添加了这一点。再次感谢。 - eestein
2
Bougarfaoui,我将这个标记为答案,因为我现在能够找到问题了 :) 在你的回答之后,我决定更仔细地查看代码,我确实应该返回它(即使概念对我来说仍然有点奇怪,因为它被重新抛出),但问题是我的包装方法的预期返回。一旦我将其更改为预期Observable<T>,它就起作用了。谢谢。 - eestein
1
请注意,在 RxJS 更新后,命令现在是 Observable.throwError(而不仅仅是 .throw)。 - VSO
throwError(response); 或 throw Error(err); - Enrico
3
我遇到了 Property 'throwError' does not exist on type 'typeof Observable'. ts(2339)(RxJS 7.4)的问题。throw也出现了同样的情况。 - Jeremy Thille

11
有时候,当你调用catch时没有使用箭头函数,就像下面这样:
getUserList() {
    return this.http.get(this.constURL + '/api/url/here', this.headerOptions)
    .catch(this.handleError);
}

handleError(error: Response) {
    if (error.status == 500) {      
      this.router.navigate(['/login']);
    } else {
      return Observable.throw(error);
    }
}

然后它会报错:

ERROR TypeError: Cannot read property 'navigate' of undefined not getting this

因为在handleError函数中,this对象是无法访问的。如果您控制台输出this.router,您将得到undefined。 所以这个对象不起作用,也不能获取路由器的所有可用方法。

所以您必须在此处使用箭头函数,如下所示:

getUserList() {
    return this.http.get(this.constURL + '/api/url/here', this.headerOptions)
    .catch(error => { 
      return this.handleError(error);
    });
}

handleError(error: Response) {
    if (error.status == 500) {      
      this.router.navigate(['/login']);
    } else {
      return Observable.throw(error);
    }
}

如果您的 handlerError 函数未声明返回类型,则会再次抛出错误,如下所示:

Argument of type '(error: any) => void' is not assignable to parameter of type...

因此,对于 handlerError 函数,声明返回类型是必要的。

请查看此处了解详情。作者已经非常清楚地解释了所有可能的错误和解决方案……这对我很有帮助。


你真的不应该粘贴一段来自与 OP 的答案无关的不同应用程序的生产代码。这会让阅读答案的人感到困惑,对 OP 来说也没有太大帮助。 - tshm001
嗨tshm001,我认为我尽力解释了OP问题所需的代码。这不是生产代码,但由于添加了一些实际服务名称而变得可读...如果需要更改,请告诉我,我会做出更改..谢谢 - Prashant M Bhavsar

10

这是一个关于Angular 6和RXJS 6的答案。

在你的请求函数中,它会类似于这样。请注意,catch 已被替换为 catchError,而 Observable.throw 现在可以用 throwError 替代。此外,在RXJS 6中,我们使用管道加入一系列我们希望执行的功能,而不是以前的点链接。

//In your service

getData(url: string): Observable<any> {
    let options = this.getHTTPOptions();
    return this.http.get<any>(url, options).pipe(
          catchError( (err: any, caught: Observable<any>) => { return 
        throwError(this.generalErrorHandler(err, caught)) } ) );
}

接下来您可以添加错误处理程序。关键是在上面的catchError函数中指定关键字return并在处理程序中返回错误。 箭头(=>)允许您将调用函数的上下文传递到错误处理程序中,这意味着您可以执行很酷的操作,例如this.router.navigate(['someroute']);(如果您已经在服务中导入了路由器)。

//In your service

  generalErrorHandler(error: any, caught: Observable<any>): Observable<any> {
    console.log('error caught: ', error);
    if( error.error.status == "INVALID_TOKEN" || error.error.status == "MAX_TOKEN_ISSUE_REACHED"){
      console.log('token has expired');
      this.logout();
      return error;
    }
    return error;
  }

让这个工作的一些关键导入:

//Imports for the service

import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { Http, Response } from '@angular/http';
import { catchError, map } from 'rxjs/operators';
import { Observable, throwError, of} from 'rxjs';

最后,订阅请求以获取您的数据:

//In your component, don't forget to import your service

let response$ = this.someService.getData('url here');
response$.subscribe( 
    data => { console.log('do stuff to data here', data); },
    err => { console.log("couldn't get data, maybe show error to user"); },
    () => { console.log('function that is called upon finish'); }
);

9
 return Observable.throw(error);

Observable.throw已经被弃用,拦截器中应该使用throwError操作符,像这样:

intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
   return next.handle(request).pipe(
    catchError(err => {
      if (err.status === 401) {
       // remove Bearer token and redirect to login page
        this.router.navigate(['/auth/login']);
      }
      return throwError( err );
    }));
}

1
我收到了 Property 'throwError' does not exist on type 'typeof Observable'. ts(2339) (RxJS 7.4) 的错误信息。 - Jeremy Thille
import { throwError } from 'rxjs';(尽管在v8中似乎已被标记为过时) - 8bitjunkie

1

目前在Angular 14中,您可以使用Error(err.error.message);来抛出错误,并且这个问题对我来说已经解决了。

示例:

 handleError(err: any): Observable<any> 
{return new Error(err.error.message);}


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