Почему Typescript считает, что async / await возвращает значение, заключенное в обещание?

Я хочу преобразовать цепочку обещаний в async / await, но Typescript жалуется на типизацию.

TS2322: Тип IHttpPromiseCallbackArg ‹IResp> не может быть назначен типу IResp ...

Я думал, что await вернет обычное значение, а не обещание. Я ошибся? Если да, то как я могу назначить типизацию, чтобы нужный код компилировался?

Я думал, что await вернет то же значение, что и первый аргумент в обратном вызове .then. Я ошибся?

Старый код:

handleSubmit(form) {
    const params = this.getParams(form);

    this.myAsyncRequest(params)
       .then((resp:IResp) => this.processResp(resp))
       .catch((e:IServerError) => this.handleError(e));
 }

Желаемый новый код:

async handleSubmit(form) {
    const params = this.getParams(form);

    try {
        const resp:IResp = await this.myAsyncRequest(params); //typing error with "const resp:IResp"
        this.processResp(resp);
    } catch (e:IServerError) {
        this.handleError(e);
    }
}

Желаемый код все равно не работает, если я удалю тип возврата в myAsyncRequest; Я предполагаю, что Typescript выводит непосредственно из библиотеки AngularJS.

myAsyncRequest(params:IParams):IHttpPromise<IResp> {
    return $http.post('blah', data);
}

Если я удалю "IResp" из объявления const resp, processResponse сообщит, что IHttp ‹IResp> не равно IResp ...

processResp(resp:IResp) {
    //do stuff
}

person user2954463    schedule 17.10.2017    source источник
comment
Тип IHttpPromiseCallbackArg не является обещанием. Это уже реальный результат вызова функции. См. definedtyped.org/docs/angular-translate- -angular-translate /   -  person NineBerry    schedule 17.10.2017
comment
Я могу переформулировать свой вопрос так: я думал, что await вернет то же значение, что и первый аргумент в обратном вызове .then. Я ошибся?   -  person user2954463    schedule 17.10.2017
comment
Ты прав. Но вы ошибаетесь относительно того, какой тип первого параметра в функции обратного вызова then. См. определенноtyped.org/docs/angularjs--angular-route / interfaces /   -  person NineBerry    schedule 17.10.2017
comment
Возможно, вы используете неправильное определение типа для того, что используете на самом деле. Но нам нужен полноценный рабочий пример, чтобы сказать это определенно.   -  person NineBerry    schedule 17.10.2017


Ответы (2)


Ваш вопрос «Я думал, что await вернет то же значение, что и первый аргумент в обратном вызове .then. Я ошибаюсь?».

Нет, ты абсолютно прав. Но вы ошибаетесь насчет первого аргумента обратного вызова .then.

Вы определяете myAsyncRequest для возврата IHttpPromise<IResp>. Но IHttpPromise<T> определяется как наследование IPromise следующим образом:

type IHttpPromise<T> = IPromise<IHttpPromiseCallbackArg<T>>;

Итак, IHttpPromise<T> - это обещание, которое возвращает IHttpPromiseCallbackArg<T> обратно, где фактические данные типа T находятся в свойстве data IHttpPromiseCallbackArg<T>.

Итак, старый вариант кода, который мы видим в вопросе:

handleSubmit(form) {
    const params = this.getParams(form);

    this.myAsyncRequest(params)
       .then((resp:IResp) => this.processResp(resp))
       .catch((e:IServerError) => this.handleError(e));
 }

на самом деле не должен компилироваться без ошибок в TypeScript, когда myAsyncRequest определено для возврата IHttpPromise.

Как это исправить:

async handleSubmit(form) {
    const params = this.getParams(form);

    try {
        const httpResp:IHttpPromiseCallbackArg<IResp> = await this.myAsyncRequest(params); 
        const resp: IResp = httpResp.data;
        this.processResp(resp);
    } catch (e:IServerError) {
        this.handleError(e);
    }
}

Примечание. В последних определениях типов для angular тип IHttpPromiseCallbackArg<T> фактически называется IHttpResponse<T>.

Может быть, в вашем коде вы определили IResp как IHttpResponse<Something>? Тогда у вас просто конфликт со старым названием IHttpPromiseCallbackArg. Затем получите новейшие определения типов от DefinentyTyped, в которых используется новое имя. И вам также придется изменить определение myAsyncRequest на:

myAsyncRequest(params:IParams):IHttpPromise<Something> {
person NineBerry    schedule 17.10.2017

Строка, содержащая await, действительно ожидает разрешенного значения, но поскольку сама функция является асинхронной (чтобы разрешить все, что ожидает), вы получаете обратно обещание.

Пример ... в приведенном ниже коде вы можете использовать x как простое число (хотя delay возвращает обещание) и снова для y - так что все, что вы ожидаете, разрешено, поэтому вы можете использовать его больше, как если бы он был синхронным .

Асинхронная функция, которая не выглядит так, как будто возвращает обещание, теперь делает это.

Это может показаться сбивающим с толку, потому что кажется, что он «инвертирует обещания», но он сдвигает then на верхний уровень (у вас могут быть асинхронные функции, вызывающие другие асинхронные функции и т. Д.).

function delay(ms: number) {
    return new Promise<number>(function(resolve) {
        setTimeout(() => {
            resolve(5);
        }, ms);
    });
}


async function asyncAwait() {
    let x = await delay(1000);
    console.log(x);

    let y = await delay(1000);
    console.log(y);

    return 'Done';
}

asyncAwait().then((result) => console.log(result));
person Fenton    schedule 17.10.2017
comment
Так что, в конце концов, мне все равно нужно куда-нибудь позвонить .then? - person user2954463; 17.10.2017
comment
Вы можете по-прежнему вызывать then на самом верху (в некоторых случаях, когда вы передаете свою функцию чему-то другому, вам не придется). - person Fenton; 17.10.2017
comment
Что с отрицательным голосом? Какие-нибудь рекомендации по улучшению ответа? - person Jonathan Smith; 17.10.2017
comment
Это не отвечает на вопрос, который, по-видимому, является неправильным пониманием типов, возвращаемых функцией. Тип IHttpPromiseCallbackArg не является обещанием, как предполагает спрашивающий. - person NineBerry; 17.10.2017
comment
Я пытался ответить на вопрос, который, как мне казалось, await вернет обычное значение, а не обещание. Я ошибся?' - person Fenton; 18.10.2017