必要時也可以用 any

使用了 TypeScript 之後,對於型別就非常敏感,都會要求自己要將傳入參數的型別與回傳型別明確指定,但 Protractor 在 page object 常用的 getText(),到底回傳型別是什麼呢?

Version

Angular CLI 1.1.2
Angular 4.2.3
Protractor 5.1.2

Symptoms


e2e/app.po.ts

1
2
3
4
5
6
7
8
9
10
11
import { browser, by, element } from 'protractor';

export class NG4DemoPage {
navigateTo() {
return browser.get('/');
}

getParagraphText() {
return element(by.css('app-root h1')).getText();
}
}

在 Angular CLI 專案預設的 Protractor 範例,其 page object 的 nagivateTo()getParagraphText() 並沒有加上回傳型別,既然使用了 TypeScript,就希望能盡量加上型別,由編譯器替我們檢查與保護。

promise000

get() 我們得知其回傳型別為 wdpromise.Promise<any>

promise001

但實際替回傳型別加上 wdpromise.Promise<any> 之後,language service 會抱怨找不到 wdpromise namespace。

promise002

getText() 則完全沒提供任何回傳型別資訊,則 getParagraphText() 該回傳什麼型別呢?

promise005

實際執行 ng e2e,結果當然也是編譯失敗。

Recipes


由於 getText() 之後可以用 then(),在觀念上知道 getText() 回傳的是 Promise

promise004

實際加上回傳型別 Promise<string>,language service 抱怨 promise.Promise<string>Promise<string> 不相容,試試看回傳 promise.Promise<string> 看看。

promise006

改成回傳 promise.Promise<string> 之後,另外加上 import { promise } from 'selenium-webdriver'; 之後,language service 就不再抱怨了。

promise.Promise 看起來很怪,不像我們常用的 TypeScript 寫法,事實上,小寫的 promise 為 namespace,而 Promise<string> 才是我們所熟悉的 Promise

promise007

藉由剛剛的經驗,將 wdpromise.Promise<any> 改成 promise.Promise<any> 試試看,結果 language service 完全不再抱怨了。

promise008

實際跑 ng e2e,TypeScript 編譯成功,也可以成功跑完測試。

實務上真的要這樣寫回傳型別嗎?

protractor/exampleTypescript/angularPage.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Because this file references protractor, you'll need to have it as a project
// dependency to use 'protractor/globals'. Here is the full list of imports:
//
// import {browser, element, by, By, $, $$, ExpectedConditions}
// from 'protractor/globals';
//
import {browser, element, by} from 'protractor';

export class AngularHomepage {
nameInput = element(by.model('yourName'));
greeting = element(by.binding('yourName'));

get() {
browser.get('http://www.angularjs.org');
}

setName(name: string) {
this.nameInput.sendKeys(name);
}

// getGreeting returns a webdriver.promise.Promise.<string>. For simplicity
// setting the return value to any
getGreeting(): any {
return this.greeting.getText();
}
}

在 Protractor 官網實際示範了應該如何用 TypeScript 寫 page object。

21 行

1
2
3
4
5
// getGreeting returns a webdriver.promise.Promise.<string>. For simplicity
// setting the return value to any
getGreeting(): any {
return this.greeting.getText();
}

getGreeting() 用的正是 getText(),Protractor 官方也認為 webdriver.promise.Promise.<string> 實在太麻煩了,用 any 即可。

promise009

若你跟我一樣有型別強迫症,回傳 any 即可。

Conclusion


  • 雖然 TypeScript 是強型別,但 any 也不是不能用,除非能說出理由,在這裡就是因為 webdriver.promise.Promise.<string> 實在太麻煩了,連 Protractor 官網也建議直接用 any 即可。

Reference


Protractor, angularPage.ts

2017-06-30