2017-10-18 82 views
0

试图学习一些Angular 4,并得到了这个问题。打字稿,承诺和倍数回复类型

我有一个REST服务器(Spring Boot),它有一个端点来登录用户,如果登录成功,它将响应头部中的JWT标记,否则用401或500(if出现问题)。

因此,要检查登录,我用下面的代码(服务):

export const TOKEN_NAME = 'jwt_token'; 
const AUTH_HEADER_KEY = 'Authorization'; 
const AUTH_PREFIX = 'Bearer'; 

@Injectable() 
export class AuthService { 

    private headers = new HttpHeaders({ 'Content-Type': 'application/json' }); 

    constructor(private http: HttpClient) { } 

    login(username: string, password: string): Promise<boolean> | Promise<never> 
    { 
    const credentials = { 
     username: username, 
     password: password 
    }; 

    const req = this.http.post(`http://localhost:8080/login`, credentials, { headers: this.headers, observe: 'response' }); 
    return req.toPromise() 
     .then(r => this.processLoginResponse(r)) 
     .catch(e => this.handleLoginError(e)); 
    } 

    private processLoginResponse(res: HttpResponseBase): boolean { 
    if (res.header.has(AUTH_HEADER_KEY)) { 
     const authorizationHeaderValue = res.headers.get(AUTH_HEADER_KEY); 

     const regex = new RegExp(`^${AUTH_PREFIX} (.*)`); 
     const m = regex.exec(authorizationHeaderValue); 

     if (m !== undefined && m.length === 2) { 
     // TODO: store the token on localstorage 
     return true 
     } 
    } 

    return false; 
    } 

    private handleLoginError(error: HttpErrorResponse): boolean | Promise<never> { 
    if (error.status === 401) { 
     return false; 

    } else if (error.status === 403) { 
     // bad request 
     return Promise.reject(new Error('Bad request custom message')); 

    } else { 
     return Promise.reject(new Error('Something goes wrong!')); 
    } 
    } 
} 

所以,在我AuthService,该login方法可以返回一个布尔值(承诺)或错误。

然后,在我的组件,如果我尝试使用下面的代码:

const loginResult = this.authService.login('john_smith', 'secret123').then(r => { console.log(r); });

我得到了一个错误,用下面的内容:

TS2349:Cannot invoke an expression whose type lacks a call signature. Type '(<TResult1 = boolean, TResult2 = never>(onfulfilled?: (value: boolean) => TResult1 | PromiseLike<...' has no compatible call signatures.

没有意识如何纠正这一点。

+0

难道这只是一个错字...'Promisse '(double-s)? – Fenton

+0

ops。抱歉。这是一个错字!现在纠正 –

回答

1

A Promise<boolean>是一个承诺,如果解决了这个问题,它将使用boolean参数调用它的回调函数。

A Promise<never>是一个承诺,解决时用never参数调用它的回调函数。但是没有never值,所以Promise<never>永远不能解决。

好的,所以,你声明login()返回Promise<boolean> | Promise<never>。这意味着它返回或者 a Promise<boolean>Promise<never>。现在,如果您将其中一个交给我,当我打电话给then()时,我可以传递什么类型的参数?那么,如果这是一个Promise<boolean>我可以给你一个boolean。但如果这是一个Promise<never>我只能给你一个never。但我不知道它是哪一个,因为你给我的东西可以是或者是其中的一个。所以我可以安全地做的唯一事情就是通过你 a booleannever。所以这只是一个never。糟糕,这不是你想要的。

你得到的具体错误是因为TypeScript won't allow you to call a method on a union of types where the method signatures differ。但即使你解决了这个错误,唯一可以安全传递给then()的是never类型。这不可能是你想要的。


让我们来备份吧。

是否要login()返回Promise<boolean> a Promise<never>?或者你想要它返回Promise<boolean | never>?意思是,承诺在解决时,使用 a booleannever来呼叫其回调。换句话说,一个承诺,呼吁它的回调与boolean或永远不会调用它的回调。换句话说,一个Promise<boolean>。如果您将退货类型login()更改为Promise<boolean>,那么承诺如果得到解决,将收到boolean。这让你可以拨打then()就可以了:

const loginResult = this.authService.login('john_smith', 'secret123').then(r => { console.log(r); }); // okay 

这样更好吗?希望有所帮助;祝你好运!

+0

我喜欢'login'函数返回'Promise '或者我可以处理的错误。因此,我将'login'方法的返回类型更改为'Promise '(仅),并将'handleLoginError'返回类型为'boolean |错误'(使用'return new Error')。现在,我没有编译器错误,但无法捕获错误('... then(r => {console.log(r);})。catch(e => {console.error(e);} );')< - console.error即使在后端响应不同于OK或无效登录时也不会调用(200,203或401) –

+0

这似乎是一个单独的问题。无论你声明'login()'返回类型是什么,你的运行时代码总是有这个问题。 – jcalz

+0

不幸的是,对于第二个问题我没有很好的答案。 Angular的'Observable'通过rxjs变成了'Promise',我不知道错误在哪里被捕获。最好由角度/ rxjs专家回答,我不是。祝你好运! – jcalz

0

Promise<never> - 我认为这是导致它的原因。 “never”是一种特殊的TypeScript类型,用于标记从不返回的方法 - 例如,它会引发异常或关闭整个“机器” - nodejs运行时。如果您想标记未返回值的方法,则您需要执行Promise<void>

+0

给我同样的错误'不能调用其类型缺少呼叫签名的表达式。类型'((onfulfilled ?:(value:void)=> TResult1 | PromiseLike

+0

编译器指出了什么地方?您需要更改**所有**签名'Promise '到'Promise '。此外,你的tsc版本是什么? –

+0

已经改变了所有函数的签名(在'AuthService'中,函数'login'和'handleLoginErrror')。 ('this.authService.login('foo','bar')。然后(r => {console.log(r);});'tsc版本是2.4.1 –