ПрограммированиеFullstack разработчик

Как работает типизация асинхронных функций и Promise в TypeScript? Как безопасно описывать возвращаемые значения, ловить ошибки типизации, в чем отличие от обычных функций? Приведите примеры.

Проходите собеседования с ИИ помощником Hintsage

Ответ.

В 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 и промис отклонялся с другим типом значения. Это привело к неявному смешиванию ошибок и валидных значений, и появлению багов в логике обработки результатов промисов.