无法将布尔值的Promise用作Typescript中的thenable构造?

Sel*_*ena 4 javascript promise typescript protractor

我正在将量角器页面对象库从JavaScript转换为Typescript。我有一个静态实用程序方法,该方法会刷新直到存在某个元素(或达到超时限制)为止。

由于某种原因,我无法将boolean有价值的诺言用作thenable构造,也无法弄清原因。错误消息是error TS2345: Argument of type '(value: boolean) => Promise<{}> | undefined' is not assignable to parameter of type '((value: boolean) => {} | IThenable<{}>) | undefined'. Type '(value: boolean) => Promise<{}> | undefined' is not assignable to type '(value: boolean) => {} | IThenable<{}>'. Type 'Promise<{}> | undefined' is not assignable to type '{} | IThenable<{}>'. Type 'undefined' is not assignable to type '{} | IThenable<{}>'.

下面的源代码带有注释,显示了编译错误发生的位置。

我在要转换为Typescript的纯JavaScript版本的框架中使用了这种机制。我需要怎么做才能将此方法转换为可以编译的Typescript?

import {browser, element, ElementFinder, ExpectedConditions} from 'protractor';
import * as wd from 'selenium-webdriver';
import {By} from "selenium-webdriver";

export class ExtendedExpectedConditions {

    public static refreshUntilElementIsPresent(element: ElementFinder,  numberOfSeconds: number = 30000,
        refreshInterval: number = 5000): void {
        this.refreshElement(element, numberOfSeconds, refreshInterval);
    }

    protected static refreshElement(element: ElementFinder, numberOfSeconds: number = 30000, refreshInterval:
        number = 5000) {


        //This line throws the compile error
        element.isPresent().then(value => {
            if (!value) {
                if (numberOfSeconds <= 0) {
                    return new wd.promise.Promise(function (resolve, reject) {
                        reject('Element cannot be found after expected retry numbers');
                    })
                }
                browser.sleep(refreshInterval).then(() => {
                    browser.refresh().then(() => this.refreshUntilElementIsPresent(element, numberOfSeconds -
                    (refreshInterval / 1000)));
                });
            }
       });
    }
}
Run Code Online (Sandbox Code Playgroud)

我的“ package.json”如下:

{
  "name": "my-project",
  "version": "1.0.0",
  "description": "A test suite",
  "scripts": {
    "tsc": "tsc",
    "pretest": "npm run tsc",
    "test": "node_modules/protractor/bin/protractor tmp/conf.js",
    "start_selenium": "node_modules/protractor/node_modules/webdriver-manager/bin/webdriver-manager start",
    "update_selenium": "node_modules/protractor/node_modules/webdriver-manager/bin/webdriver-manager update"
  },
  "author": aperson@someplace.com,
  "dependencies": {
    "@types/jasmine": "^2.5.52",
    "@types/jasminewd2": "^2.0.2",
    "@types/node": "^7.0.31",
    "any-promise": "^1.3.0",
    "jasmine-reporters": "^2.2.1",
    "protractor": "^5.1.2",
    "typescript": "^2.3.4"
  }
}
Run Code Online (Sandbox Code Playgroud)

我的tsconfig.json在下面:

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "declaration": false,
    "noImplicitAny": false,
    "outDir": "tmp",
    "types": ["jasmine", "node"],
    "strict": true
  },
  "exclude": [
    "node_modules"
  ]
}
Run Code Online (Sandbox Code Playgroud)

我的conf.ts文件如下:

import {Config, browser, protractor} from "protractor";

let testsTimeout = 3600000;
let delayBrowserTimeInSeconds = 0;

export let config: Config = {
    framework: 'jasmine2',
    rootElement: 'body',
    seleniumServerJar:'../node_modules/protractor/node_modules/webdriver-manager/selenium/selenium-server-standalone-3.4.0.jar',
    chromeDriver: '../node_modules/protractor/node_modules/webdriver-manager/selenium/chromedriver_2.30',
    specs: ['tests/*Spec.js'],
    capabilities: {
        browserName: 'chrome',
        acceptSslCerts: true,
        trustAllSSLCertificates: true,
        chromeOptions: {
            args: ['--no-sandbox']
        },
    },
    baseUrl: 'https://www.someurl.com',

    jasmineNodeOpts: {
        defaultTimeoutInterval: testsTimeout,
        showColors: true,
        isVerbose: true
    },

    onPrepare: () => {

        let origFn = browser.driver.controlFlow().execute;

        browser.driver.controlFlow().execute = function () {
            let args = arguments;

            origFn.call(browser.driver.controlFlow(), function () {
                return protractor.promise.delayed(delayBrowserTimeInSeconds * 100);
            });

            return origFn.apply(browser.driver.controlFlow(), args);
        };

        setTimeout(() => {
            browser.driver.executeScript<[number, number]>(() => {
                return [
                    window.screen.availWidth,
                    window.screen.availHeight
            ];
            }).then((result: [number, number]) => {
                browser.driver.manage().window().setSize(result[0], result[1]);
                browser.driver.manage().window().maximize();
            });
        });

    },

    getPageTimeout: 120000,
    allScriptsTimeout: testsTimeout
};
Run Code Online (Sandbox Code Playgroud)

Dun*_*can 5

您真正的问题似乎是类型库的作者对该then方法的回调参数定义不正确。您在问题中稍微输入了错误消息,这使得查看正在发生的事情变得更加困难。

src/test.ts(17,34): error TS2345: Argument of type '(value: boolean) => Promise<{}> | undefined' is not assignable to parameter of type '((value: boolean) => {} | IThenable<{}>) | undefined'.
  Type '(value: boolean) => Promise<{}> | undefined' is not assignable to type '(value: boolean) => {} | IThenable<{}>'.
    Type 'Promise<{}> | undefined' is not assignable to type '{} | IThenable<{}>'.
      Type 'undefined' is not assignable to type '{} | IThenable<{}>'.
Run Code Online (Sandbox Code Playgroud)

因此,您提供的回调.then类型为,(value: boolean) => Promise<{}> | undefined也就是说,它返回Promise或返回undefined

但是.then()期望给出((value: boolean) => {} | IThenable<{}>) | undefined (这是您在问题中输掉一个闭合的')'的意思,即函数或没有回调。当您给它提供一个函数时,我们可以忽略该函数undefined,因此我们必须给它提供一个返回值或a的函数IThenable<something>。该代码的作者已决定then不允许返回in的回调undefined

因此,短期修复很简单:更改.then回调,使其始终返回结果。

较长期的解决方法是将一个问题报告给Selenium Webdriver的打字稿绑定的作者,并要求他们允许回调返回{} | IThenable<{}> | undefined

您应该找到适合您的以下代码:

export class ExtendedExpectedConditions {

    public static refreshUntilElementIsPresent(element: ElementFinder,  numberOfSeconds: number = 30000,
        refreshInterval: number = 5000): void {
        this.refreshElement(element, numberOfSeconds, refreshInterval);
    }

    protected static refreshElement(element: ElementFinder, numberOfSeconds: number = 30000, refreshInterval:
        number = 5000) {


        //This line throws the compile error
        element.isPresent().then(value => {
            if (!value) {
                if (numberOfSeconds <= 0) {
                    return wd.promise.rejected('Element cannot be found after expected retry numbers');
                }
                browser.sleep(refreshInterval).then(() => {
                    browser.refresh().then(() => this.refreshUntilElementIsPresent(element, numberOfSeconds -
                    (refreshInterval / 1000)));
                });
            }
            return 42; // webdriver `.then` callback must return a result.
       });
    }
}
Run Code Online (Sandbox Code Playgroud)

另外,由于某种原因,Webdriver Promise的类型定义未声明对象本身确实包含的.resolve().reject()方法,但是您可以使用该promise.rejected()函数作为创建立即被拒绝的承诺的更简单方法。