Не уверен, почему в этом коде Typescript требуется приведение типов. Мое сумасшествие или языковое ограничение?

Я использую определения типизации (DefinitelyTyped) для bluebird, и у меня возникла проблема с Promise.attempt<T>.

Я не понимаю, зачем мне нужно следующее приведение: https://github.com/brandf/upstream/blob/0b38a42a/src/domain.ts#L73

return Promise.attempt<Data>(() => {
    return <Data>handler(matchResult, id);
}); 

Обратите внимание, что тип обработчика возвращает Data|Promise<Data>. Без приведения возвращаемого значения к <Data> я получаю следующую ошибку:

src/domain.ts(72,50): error TS2345: Argument of type '() => Data |
Promise<Data>' is not assignable to parameter of type '() => Data'.
  Type 'Data | Promise<Data>' is not assignable to type 'Data'.
    Type 'Promise<Data>' is not assignable to type 'Data'.

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

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/bluebird/bluebird.d.ts#L57-L58

attempt<T>(fn: () => PromiseLike<T>, args?: any[], ctx?: any): Promise<T>;
attempt<T>(fn: () => T, args?: any[], ctx?: any): Promise<T>;

Я ожидаю, что Typescript увидит обе перегрузки и распознает, что () => Data|Promise<Data> совпадает с () => Data плюс () => Promise<Data>, но, похоже, это не так.

Я что-то упускаю? Является ли это ограничением Typescript или просто плохими определениями типов?

Я могу изменить определения типа bluebird, чтобы иметь одну перегрузку, которая занимает () => T|Promise<T>, тогда мне не нужно приведение, но я все же хотел бы понять, почему это необходимо, учитывая существующие перегрузки.


person Brandon Furtwangler    schedule 03.02.2016    source источник


Ответы (2)


Как указывает Мартин, проблема в том, что TypeScript не может автоматически определить, как разложить этот тип объединения или составить перегрузки и убедитесь, что они совместимы в этом случае. На самом деле проблема заключается в определениях типов для bluebird. Вместо двух перегрузок:

attempt<T>(fn: () => PromiseLike<T>, args?: any[], ctx?: any): Promise<T>;
attempt<T>(fn: () => T, args?: any[], ctx?: any): Promise<T>;

Это должно быть переписано как

attempt<T>(fn: () => T | PromiseLike<T>, args?: any[], ctx?: any): Promise<T>;

Я отправил запрос на включение в DefinitelyTyped, чтобы исправить эту и некоторые подобные проблемы.

person Daniel Rosenwasser    schedule 03.02.2016

Для вашей проблемы существует открытая проблема https://github.com/Microsoft/TypeScript/issues/1805 . :-)

person Martin Vseticka    schedule 03.02.2016