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”:

TYPESCRIPT
// 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

TYPESCRIPT
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

TYPESCRIPT
// 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

TYPESCRIPT
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;
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
// 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:

TYPESCRIPT
// 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:

TYPESCRIPT
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

TYPESCRIPT
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:

TYPESCRIPT
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

TYPESCRIPT
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

TYPESCRIPT
// 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

TYPESCRIPT
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

TYPESCRIPT
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

TYPESCRIPT
// 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

TYPESCRIPT
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();
▶ Experimente

Saída:

TEXT 📖 Somente leitura
// Executed successfully


5. Iteradores assíncronos

(1) AsyncIterable com for await...of

TYPESCRIPT
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

TYPESCRIPT
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

TYPESCRIPT
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));
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
User1 has 1 post(s)

❓ Perguntas Frequentes

P: Uma função async precisa retornar um Promise? R: Recomenda-se especificá-lo explicitamente. O TypeScript pode inferir que uma função async retorna um Promise, mas especificá-lo explicitamente async 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.all falhar? R: Promise.all funciona segundo o princípio “tudo ou nada” — se qualquer Promessa for rejeitada, toda a operação all será rejeitada. Se você precisar que “todas sejam concluídas (independentemente do sucesso ou da falha)”, use Promise.allSettled. Se precisar que “a primeira seja bem-sucedida”, use Promise.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

📝 Exercícios

  1. 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”.
  2. 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.
  3. 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).
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%