O que é Effect-TS
Effect-TS é uma biblioteca que implementa programação funcional em TypeScript. Oferece tratamento de erros type-safe, injeção de dependências e processamento concorrente, permitindo construir aplicações robustas.
Conceitos Básicos
Tipo Effect
Effect<A, E, R> possui três parâmetros de tipo.
Effect<
A, // Tipo do valor de retorno em caso de sucesso
E, // Tipo dos erros que podem ocorrer
R // Dependências necessárias (Requirements)
>
Uso Básico
Criando Effects
import { Effect } from 'effect';
// Effect que sucede
const success = Effect.succeed(42);
// Effect que falha
const failure = Effect.fail(new Error('Something went wrong'));
// Effect assíncrono
const asyncEffect = Effect.promise(() => fetch('/api/data').then(r => r.json()));
// Capturar exceções
const safe = Effect.try({
try: () => JSON.parse(invalidJson),
catch: (error) => new ParseError(error)
});
Executando Effects
import { Effect } from 'effect';
const program = Effect.succeed(42);
// Execução síncrona
const result = Effect.runSync(program);
// Execução assíncrona
const promise = Effect.runPromise(program);
// Promise (retorna erro como tipo Either)
const exit = await Effect.runPromiseExit(program);
Tratamento de Erros
Erros Type-Safe
import { Effect, Data } from 'effect';
// Definição de erros customizados
class NetworkError extends Data.TaggedError('NetworkError')<{
message: string;
}> {}
class ValidationError extends Data.TaggedError('ValidationError')<{
field: string;
message: string;
}> {}
// Função que pode gerar erros
const fetchUser = (id: string): Effect.Effect<
User,
NetworkError | ValidationError
> => {
if (!id) {
return Effect.fail(new ValidationError({ field: 'id', message: 'Required' }));
}
return Effect.tryPromise({
try: () => fetch(`/api/users/${id}`).then(r => r.json()),
catch: () => new NetworkError({ message: 'Failed to fetch' })
});
};
Tratando Erros
const program = fetchUser('123').pipe(
// Capturar erro específico
Effect.catchTag('NetworkError', (e) =>
Effect.succeed({ name: 'Fallback User' })
),
// Capturar todos os erros
Effect.catchAll((e) => Effect.succeed({ name: 'Default' }))
);
Injeção de Dependências
Definindo Serviços
import { Context, Effect, Layer } from 'effect';
// Interface do serviço
class Database extends Context.Tag('Database')<
Database,
{
query: (sql: string) => Effect.Effect<unknown[]>;
}
>() {}
// Função que usa o serviço
const getUsers = Effect.gen(function* () {
const db = yield* Database;
return yield* db.query('SELECT * FROM users');
});
// Implementação
const DatabaseLive = Layer.succeed(Database, {
query: (sql) => Effect.promise(() => pool.query(sql))
});
// Mock para testes
const DatabaseTest = Layer.succeed(Database, {
query: () => Effect.succeed([{ id: 1, name: 'Test' }])
});
// Execução
const program = getUsers.pipe(
Effect.provide(DatabaseLive)
);
Processamento Concorrente
Execução Paralela
import { Effect } from 'effect';
const task1 = Effect.promise(() => fetch('/api/users'));
const task2 = Effect.promise(() => fetch('/api/posts'));
const task3 = Effect.promise(() => fetch('/api/comments'));
// Executar todos em paralelo
const all = Effect.all([task1, task2, task3], { concurrency: 'unbounded' });
// Limitar paralelismo
const limited = Effect.all([task1, task2, task3], { concurrency: 2 });
// Obter o primeiro a completar
const race = Effect.race([task1, task2, task3]);
Gerenciamento de Recursos
import { Effect } from 'effect';
const acquire = Effect.promise(() => pool.connect());
const release = (conn: Connection) => Effect.promise(() => conn.release());
const withConnection = Effect.acquireUseRelease(
acquire,
(conn) => Effect.promise(() => conn.query('SELECT 1')),
release
);
Pipeline
import { Effect, pipe } from 'effect';
const program = pipe(
Effect.succeed({ name: 'Alice', age: 30 }),
Effect.map(user => user.name),
Effect.flatMap(name => Effect.succeed(`Hello, ${name}!`)),
Effect.tap(greeting => Effect.log(greeting))
);
// Ou
const program2 = Effect.succeed({ name: 'Alice', age: 30 }).pipe(
Effect.map(user => user.name),
Effect.flatMap(name => Effect.succeed(`Hello, ${name}!`))
);
Sintaxe Generator
import { Effect } from 'effect';
const program = Effect.gen(function* () {
const user = yield* fetchUser('123');
const posts = yield* fetchPosts(user.id);
const comments = yield* fetchComments(posts[0].id);
return { user, posts, comments };
});
Agendamento
import { Effect, Schedule } from 'effect';
// Estratégia de retry
const retry = Schedule.exponential('100 millis').pipe(
Schedule.compose(Schedule.recurs(3))
);
const program = fetchData.pipe(
Effect.retry(retry)
);
// Execução periódica
const repeated = Effect.repeat(
fetchData,
Schedule.spaced('1 minute')
);
Conclusão
Effect-TS adiciona poderosas funcionalidades de programação funcional ao TypeScript. Com tratamento de erros type-safe, injeção de dependências e processamento concorrente, é possível construir aplicações com alta manutenibilidade e confiabilidade.
← Voltar para a lista