2017-10-18 84 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 –