TypeScript: Programação assíncrona e tipos no TypeScript
Última atualização: 2026-08-26
A programação assíncrona é um padrão fundamental no JavaScript — o TypeScript oferece suporte completo a tipos para operações assíncronas por meio de Promises genéricas e async/await.
1. Noções básicas sobre o tipo Promise
(1) Tipos genéricos de promessas
Uma Promise é um tipo genérico — Promise<T> indica que “um valor do tipo T será produzido no futuro”:
// Synchronization Functions——Direct Return Value
function getUserSync(): string {
return "Charlie";
}
// Asynchronous Functions——Back Promise<string>
function getUserAsync(): Promise<string> {
return Promise.resolve("Charlie");
}
// Simulate Web Requests
function fetchUser(id: number): Promise<{ id: number; name: string }> {
return new Promise((resolve) => {
setTimeout(() => resolve({ id, name: "User" + id }), 100);
});
}
(2) Inferência de tipos em then e catch
let promise: Promise<string> = Promise.resolve("hello");
promise
.then(value => {
// value Type automatically inferred as string
console.log(value.toUpperCase()); // ✅
return value.length; // Back number → then Chain becomes Promise<number>
})
.then(length => {
// length Type automatically inferred as number
console.log(length.toFixed(2)); // ✅
})
.catch(error => {
// error Type: any(TypeScript Unable to infer the error type)
console.log(error.message);
});
(3) Imutabilidade e segurança do tipo Promise
// Promise It is covariant.——Promise<string> Can be assigned to Promise<string | number>
let p1: Promise<string> = Promise.resolve("hello");
let p2: Promise<string | number> = p1; // ✅ Covariant Safety
// It doesn't work the other way around.
// let p3: Promise<string> = p2; // ❌ Promise<string | number> Cannot be assigned Promise<string>
▶ Exemplo: Cliente de API com segurança de tipos
interface ApiResponse<T> {
status: number;
data: T;
message: string;
}
interface User {
id: number;
name: string;
email: string;
}
interface Product {
id: number;
title: string;
price: number;
}
function apiGet<T>(url: string): Promise<ApiResponse<T>> {
// Simulation API Call
return new Promise((resolve) => {
setTimeout(() => {
resolve({
status: 200,
data: {} as T, // In actual projects, this is done by JSON.parse Result Assertion
message: "OK"
});
}, 100);
});
}
// Usage——Each request has a specific return type
async function getUser(id: number): Promise<User> {
let response = await apiGet<User>(`/api/users/${id}`);
return response.data;
}
async function getProducts(): Promise<Product[]> {
let response = await apiGet<Product[]>("/api/products");
return response.data;
}
Saída:
// Executed successfully
2. Tipos em assíncrono/await
(1) Valores de retorno das funções assíncronas
Funções assíncronas sempre retornam uma Promise — mesmo que você retorne um valor comum, o TypeScript o encapsula automaticamente:
// Explicit Return Values——Automatic packaging is Promise
async function greet(): Promise<string> {
return "Hello"; // Equivalent to return Promise.resolve("Hello")
}
// Explicit Return Promise——No double packaging
async function fetchName(): Promise<string> {
return Promise.resolve("Charlie"); // It won't turn into Promise<Promise<string>>
}
(2) Inferência de tipos com await
await desembrulha a Promise — o tipo de await Promise<T> é T:
async function example() {
let name: string = await Promise.resolve("Charlie"); // ✅ Unpack to string
let count: number = await Promise.resolve(42); // ✅ Unpack to number
let user: User = await fetchUser(1); // ✅ Unpack to User
}
(3) Cuidado com a armadilha — pode ser rejeitado
async function riskyOperation(): Promise<number> {
// This Promise possibly reject
let result = await mayFail(); // result The type is number——However, an exception may be thrown during runtime.
return result;
}
async function mayFail(): Promise<number> {
if (Math.random() > 0.5) {
throw new Error("Random failure");
}
return 42;
}
// Safe coding practice — use try/catch
async function safeOperation(): Promise<number | null> {
try {
let result = await mayFail();
return result;
} catch {
return null;
}
}
3. Tipos de utilitários Promise
(1) Aguardando — Desvendando um tipo de promessa
O TypeScript 4.5 inclui o tipo Awaited<T> — desembrulhamento recursivo de Promises:
type A = Awaited<Promise<string>>; // string
type B = Awaited<Promise<Promise<number>>>; // number(Recursive Unpacking)
type C = Awaited<string>; // string (non-Promise, returned directly)
type D = Awaited<Promise<string | number>>; // string | number
(2) Aplicação prática — Como extrair o tipo de retorno de uma função assíncrona
async function fetchUser(id: number) {
let response = await fetch(`/api/users/${id}`);
return response.json() as Promise<{ id: number; name: string }>;
}
// Extracting the Return Type of an Asynchronous Function(Remove Promise Packaging)
type UserResponse = Awaited<ReturnType<typeof fetchUser>>;
// { id: number; name: string }
(3) Tipos de utilitários de Promise personalizados
// Extract Promise Each element in the array Promise Parsed Type
type UnwrapPromiseArray<T> = {
[K in keyof T]: T[K] extends Promise<infer U> ? U : T[K];
};
type Input = [Promise<string>, Promise<number>, boolean];
type Output = UnwrapPromiseArray<Input>;
// [string, number, boolean]
4. Segurança de tipos no controle de concorrência
(1) Promise.all
async function loadDashboard() {
// Promise.all Accepting different types of Promise Array
let [users, products, stats] = await Promise.all([
fetchUsers(), // Promise<User[]>
fetchProducts(), // Promise<Product[]>
fetchStats() // Promise<Stats>
]);
// Each variable has its own type.
console.log(users.length); // User[].length
console.log(products[0].title); // Product.title
console.log(stats.totalUsers); // Stats.totalUsers
}
(2) Promise.allSettled
type SettledResult<T> = {
status: "fulfilled";
value: T;
} | {
status: "rejected";
reason: unknown;
};
async function tryMultipleApis() {
let results = await Promise.allSettled([
fetchFromApi1(), // Promise<User>
fetchFromApi2(), // Promise<User>
]);
for (let result of results) {
if (result.status === "fulfilled") {
console.log(result.value.name); // ✅ value Type: User
} else {
console.log(result.reason); // unknown
}
}
}
(3) Promise.race com Promise.any
// race——Take the result that was completed first(Whether success or failure)
async function fetchWithTimeout(url: string, ms: number) {
let result = await Promise.race([
fetch(url),
new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error("Timeout")), ms)
)
]);
return result;
}
// any——Take the first successful result(Ignore Failure)
async function fetchWithFallback() {
let result = await Promise.any([
fetchFromPrimary(), // Priority
fetchFromSecondary(), // Standby
]);
// result Type: All Promise composite types' resolved values
}
▶ Exemplo: Carregador de dados simultâneo
interface User { id: number; name: string; }
interface Post { id: number; title: string; authorId: number; }
interface Comment { id: number; postId: number; text: string; }
async function fetchAllData(userId: number) {
let [user, posts, comments] = await Promise.all([
fetchUser(userId),
fetchPosts(userId),
fetchComments(userId)
]);
return { user, posts, comments };
}
async function fetchUser(id: number): Promise<User> {
return { id, name: "User" + id };
}
async function fetchPosts(userId: number): Promise<Post[]> {
return [{ id: 1, title: "Article1", authorId: userId }];
}
async function fetchComments(userId: number): Promise<Comment[]> {
return [{ id: 1, postId: 1, text: "Great Article!" }];
}
async function main() {
let data = await fetchAllData(1);
console.log(`User:${data.user.name}`);
console.log(`Number of Articles:${data.posts.length}`);
console.log(`Number of comments:${data.comments.length}`);
}
main();
Saída:
// Executed successfully
5. Iteradores assíncronos
(1) AsyncIterable com for await...of
async function* asyncCounter(max: number): AsyncGenerator<number> {
for (let i = 0; i < max; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
async function run() {
for await (let num of asyncCounter(3)) {
console.log(num);
}
// 0 → 1 → 2(Every interval100ms)
}
(2) Tipos de geradores assíncronos
interface AsyncGenerator<T> {
next(): Promise<IteratorResult<T>>;
return(value?: any): Promise<IteratorResult<T>>;
throw(e?: any): Promise<IteratorResult<T>>;
[Symbol.asyncIterator](): AsyncGenerator<T>;
}
▶ Exemplo: Tipo utilitário Awaited na prática
interface User { id: number; name: string; }
interface Post { id: number; title: string; }
async function fetchUser(id: number): Promise<User> {
return { id, name: "User" + id };
}
async function fetchPosts(userId: number): Promise<Post[]> {
return [{ id: 1, title: "Post by " + userId }];
}
type UserType = Awaited<ReturnType<typeof fetchUser>>; // User
type PostsType = Awaited<ReturnType<typeof fetchPosts>>; // Post[]
function render(user: UserType, posts: PostsType): string {
return `${user.name} has ${posts.length} post(s)`;
}
async function main() {
let user = await fetchUser(1);
let posts = await fetchPosts(user.id);
console.log(render(user, posts));
}
Saída:
User1 has 1 post(s)
❓ Perguntas Frequentes
P: Uma função
asyncprecisa retornar umPromise? R: Recomenda-se especificá-lo explicitamente. O TypeScript pode inferir que uma funçãoasyncretorna umPromise, mas especificá-lo explicitamenteasync function fn(): Promise<T>proporciona maior clareza — isso ajuda na documentação e detecta erros em tempo de compilação. É possível omitir o tipo de retorno para funções simples, mas é recomendável especificá-lo para funções complexas.
P: Por que o tipo do erro é “desconhecido” no bloco catch de uma Promise? R: Como o JavaScript permite que qualquer valor seja lançado (não se limitando a Error), o TypeScript não pode garantir que o valor capturado seja do tipo Error. Recomenda-se realizar uma verificação de tipo no bloco catch:
if (error instanceof Error)ou usar uma asserção de tipo:error as Error.
P: O que acontece se uma das Promessas em
Promise.allfalhar? R:Promise.allfunciona segundo o princípio “tudo ou nada” — se qualquer Promessa for rejeitada, toda a operaçãoallserá rejeitada. Se você precisar que “todas sejam concluídas (independentemente do sucesso ou da falha)”, usePromise.allSettled. Se precisar que “a primeira seja bem-sucedida”, usePromise.any.
P: As funções assíncronas podem ser sobrecarregadas? R: Sim. A sobrecarga de funções assíncronas funciona exatamente da mesma forma que com as funções síncronas — as assinaturas sobrecarregadas descrevem os tipos de retorno para diferentes combinações de parâmetros (wrappers de Promise), e a implementação garante a compatibilidade das assinaturas entre todas as sobrecargas.
📖 Resumo
Promise<T>é um tipo de operação assíncrona — T é um tipo de valor que será gerado no futuro- As funções assíncronas sempre retornam uma Promise;
awaitdesembrulha a Promise para obter T Awaited<T>Desempacotando recursivamente tipos de Promise — Extraindo o tipo de retorno de funções assíncronas- O
Promise.allexecuta váriasPromisessimultaneamente e retorna uma tupla (em que cada elemento é de um tipo diferente) - Promise.allSettled aguarda todas as respostas; Promise.race seleciona a mais rápida; Promise.any seleciona a primeira que for bem-sucedida
- O gerador assíncrono
AsyncGenerator<T>funciona em conjunto com ofor await...ofpara implementar a iteração assíncrona
📝 Exercícios
- Problema básico (Dificuldade ⭐): Escreva uma função chamada
delay(ms: number): Promise<void>que retorne uma Promise que seja resolvida após ms milissegundos. Use assíncrono/await para chamá-la e implemente “imprimir uma mensagem após esperar 1 segundo”. - Problema avançado (Dificuldade ⭐⭐): Escreva uma função
retry<T>(fn: () => Promise<T>, maxRetries: number): Promise<T>— quando fn falhar, ela tentará novamente automaticamente até maxRetries vezes. Implemente isso usando try/catch e um laço. - Problema de desafio (Dificuldade ⭐⭐⭐): Implemente
concurrentLimit<T>(tasks: (() => Promise<T>)[], limit: number): Promise<T[]>— execute tarefas simultaneamente, mas não execute mais do que o número limite de tarefas ao mesmo tempo. Quando todas as tarefas estiverem concluídas, retorne uma matriz com os resultados (na mesma ordem).