В TypeScript асинхронные функции (async/await) всегда возвращают Promise. Тип возвращаемого значения указывается так: Promise<Type>. При описании функции важно явно типизировать результат, чтобы TypeScript корректно работал с типами внутри промиса. Ошибки типизации могут возникнуть, если промежуточные значения не совпадают с теми, что объявлены.
Асинхронная функция:
async function fetchUser(id: number): Promise<User> { const response = await fetch(`/api/user/${id}`); const data: User = await response.json(); return data; }
Если функция должна вернуть ошибку или отклонение, то тип промиса не должен описывать ошибку напрямую (Promise<Error>), так как отклонение промиса не типизируется, а ловится через catch.
Типизация цепочек промисов важна:
function getNumber(): Promise<number> { return Promise.resolve(42); } getNumber().then(val => val.toFixed(2)); // TypeScript знает, что val — число
Вопрос: Может ли асинхронная функция возвращать что-то, кроме промиса?
Ответ: Нет. Асинхронная функция всегда возвращает объект Promise. Если явно вернуть не-промис, TypeScript автоматически обернет возвращаемое значение в промис.
async function test() { return 1; } const result = test(); type ResultType = typeof result; // Promise<number>
История
Разработчик написал функцию без явной типизации возвращаемого значения, предполагая, что она возвращает объект определённого типа. При изменении логики функцию стали возвращать другой тип, и это не было замечено сразу, так как TypeScript, основываясь на выводе типа, не выдавал ошибку. В итоге ошибки проявились только в рантайме, когда потребитель функции попытался вызвать несуществующее свойство.
История
В одном проекте цепочки промисов были не типизированы. Попытка обращения к несуществующему методу на результате приводила к ошибкам. Так, результат then(response => response.data) считался any, и ошибка отлова полей или методов проявлялась только в рантайме. Ошибка ушла в продакшн и была обнаружена только с помощью пользователей.
История
Асинхронную функцию объявили с типом Promise<Error>, считая, что это позволит ловить ошибки, но на самом деле ошибки не пробрасывались через throw и промис отклонялся с другим типом значения. Это привело к неявному смешиванию ошибок и валидных значений, и появлению багов в логике обработки результатов промисов.