Effect: Thư viện đang cố gắng trở thành “Standard Library” cho TypeScript
Nếu bạn đã từng build một backend TypeScript đủ lớn, rất có thể bạn đã gặp những vấn đề như:
- Async function throw lỗi nhưng không biết trước sẽ fail kiểu gì
- Retry API phải tự viết
- Timeout phải tự viết
- Dependency Injection ngày càng phức tạp
- Logging, tracing, observability bị phân tán khắp nơi
- Test khó vì service phụ thuộc chồng chéo
Đây chính là nhóm vấn đề mà Effect muốn giải quyết.
Website chính thức:

Effect là gì?
Effect là một framework/thư viện TypeScript theo hướng Functional Programming (FP), được thiết kế để xây dựng các ứng dụng production-grade với:
- Typed Error Handling
- Dependency Injection
- Structured Concurrency
- Resource Management
- Retry Policies
- Observability
- Streams
- Workflows
Theo mô tả từ đội ngũ phát triển:
Effect là một hệ sinh thái công cụ để xây dựng ứng dụng TypeScript mạnh mẽ và an toàn hơn.
Thay vì chỉ là một thư viện utility, Effect cố gắng trở thành một lớp abstraction cho toàn bộ side effects trong ứng dụng.
Vấn đề của Promise và Async/Await
TypeScript hiện tại chủ yếu xử lý async bằng Promise.
Ví dụ:
async function getUser(id: string) {
const response = await fetch(`/users/${id}`)
if (!response.ok) {
throw new Error("User not found")
}
return response.json()
}
Nhìn có vẻ ổn.
Nhưng khi project lớn lên:
- Function có thể throw nhiều loại lỗi khác nhau
- Caller không biết phải handle lỗi gì
- Dependency bị ẩn
- Retry, timeout, cancellation phải tự xử lý
Compiler gần như không giúp được nhiều.
Khái niệm cốt lõi: Effect<A, E, R>
Trung tâm của thư viện là type:
Effect<A, E, R>
Ý nghĩa:
| Type | Vai trò |
|---|---|
| A | Giá trị thành công |
| E | Kiểu lỗi |
| R | Dependency cần có |
Ví dụ:
Effect<User, UserNotFound, UserRepository>
Có thể hiểu là:
Trả về User
Có thể lỗi UserNotFound
Cần UserRepository
Điểm quan trọng là compiler biết toàn bộ điều này.
Typed Errors: Error Handling có type
Trong JavaScript:
try {
await fetch(...)
} catch (err) {
// any
}
Vấn đề:
err = unknown
hoặc:
err = any
Bạn không biết chính xác function có thể fail theo cách nào.
Effect biến lỗi thành một phần của type.
Ví dụ:
Effect<User, NetworkError, never>
Compiler sẽ biết:
Có thể fail bằng NetworkError
Tư duy này khá giống:
Result<User, NetworkError>
trong Rust.
Dependency Injection bằng Type
NestJS thường viết:
@Injectable()
class UserService {
constructor(
private readonly repo: UserRepo
) {}
}
Effect lại encode dependency vào type:
Effect<User, Error, UserRepo>
Điều này giúp:
- Dependency rõ ràng hơn
- Không cần decorators
- Không cần reflection
- Dễ test hơn
Retry và Resilience
Một trong những use case phổ biến nhất:
fetch()
có thể fail vì:
- Network
- Timeout
- Rate limit
- Temporary outage
Thông thường:
for (...) {
try {
...
} catch {}
}
Effect có retry policy built-in:
Effect.retry(...)
Ví dụ:
1s
2s
4s
8s
theo exponential backoff.
Structured Concurrency
Đây là feature rất mạnh của Effect.
Ví dụ:
const users = fetchUsers()
const posts = fetchPosts()
const comments = fetchComments()
Chạy song song:
Effect.all([
users,
posts,
comments
])
Nếu một task fail:
posts fail
các task còn lại có thể bị cancel và cleanup tự động.
Cách hoạt động này tương tự:
- Kotlin Coroutines
- Go Context
- Rust Tokio
- Scala ZIO
Observability Built-in
Các hệ thống production thường cần:
- Logging
- Tracing
- Metrics
- OpenTelemetry
Thông thường phải ghép nhiều thư viện lại.
Effect được thiết kế để hỗ trợ observability ngay từ runtime.
Resource Management
Một lỗi rất phổ biến:
const connection = await db.connect()
try {
...
} finally {
connection.close()
}
Nếu code phức tạp hơn:
Database
Redis
Queue
File
Stream
việc cleanup trở nên khó kiểm soát.
Effect có hệ thống Scope và Resource Management để tự động quản lý vòng đời resource.
Hệ sinh thái của Effect
Hiện monorepo có khá nhiều package:
| Package | Chức năng |
|---|---|
| effect | Core |
| @effect/ai | AI workflows |
| @effect/ai-openai | OpenAI integration |
| @effect/cli | CLI apps |
| @effect/cluster | Distributed systems |
Nguồn:
Use Cases thực tế
Backend APIs
Rất phù hợp với:
- Node.js
- Express
- Fastify
- Hono
- NestJS
Đặc biệt khi:
Request
↓
Validate
↓
Database
↓
Cache
↓
Queue
↓
Response
có nhiều async operations.
Microservices
Effect đặc biệt mạnh ở đây.
Ví dụ:
Order Service
Inventory Service
Payment Service
Notification Service
Bạn thường cần:
- Retry
- Timeout
- Circuit Breaker
- Queue
- Tracing
Effect được thiết kế cho các workflow như vậy.
AI Agents
Đây là use case đang nổi lên gần đây.
Ví dụ:
OpenAI
↓
RAG
↓
Database
↓
Tool Call
↓
Another Model
Mỗi bước đều có thể fail.
Effect giúp:
- Retry
- Timeout
- Fallback
- Tracing
dễ quản lý hơn Promise thông thường.
Data Pipelines
Ví dụ:
Kafka
↓
Transform
↓
Postgres
↓
Redis
Effect cung cấp:
- Stream
- Queue
- PubSub
để xây dựng pipeline xử lý dữ liệu.
Những điểm trừ
Không có công cụ nào hoàn hảo.
Learning Curve cao
Đây là nhược điểm lớn nhất.
Nhiều developer quen:
await getUser()
sẽ thấy khó tiếp cận với:
pipe(
Effect.map(...),
Effect.flatMap(...)
)
hoặc:
Effect.gen(...)
Cộng đồng cũng thường xuyên nhắc đến learning curve khá nặng của Effect.
Nguồn:
- https://www.reddit.com/r/typescript/comments/1r7ez65/thoughts_on_effect/
- https://www.reddit.com/r/typescript/comments/16w3iwn/opinions_about_effectts_do_you_recommend_using_it/
Không phải thư viện "thêm vào cho vui"
Một nhận xét khá phổ biến từ cộng đồng:
Effect không phải thứ bạn "thêm" vào project. Nó là thứ bạn xây kiến trúc quanh nó.
Nghĩa là:
Dùng Effect = thay đổi cách viết ứng dụng
chứ không chỉ thêm package.
Nguồn:
Overkill cho CRUD thông thường
Nếu bạn đang làm:
- Admin Dashboard
- CMS
- Blog
- Ecommerce nhỏ
- SaaS CRUD
thì stack như:
Next.js
Prisma
Zod
TanStack Query
thường đã đủ.
Effect có thể làm tăng độ phức tạp không cần thiết.
Khi nào nên dùng Effect?
Nên cân nhắc khi project có:
- Microservices
- Event-driven architecture
- AI Agents
- Background Jobs
- Workflow Engine
- Queue Processing
- Distributed Systems
- Financial Systems
- Nhiều retry / timeout / fallback logic
Khi nào không nên dùng?
Không nên nếu:
- MVP cần ship nhanh
- CRUD application đơn giản
- Team chưa quen FP
- Chỉ muốn typed errors
Trong trường hợp chỉ cần typed errors, nhiều developer chọn:
- neverthrow
- true-myth
vì nhẹ hơn rất nhiều.
Nguồn:
Một góc nhìn thú vị
Nhiều người mô tả Effect là:
"Standard Library mà TypeScript đáng lẽ nên có."
Bởi vì nó gom rất nhiều thứ vốn đang bị phân tán:
- Error Handling
- Dependency Injection
- Retry
- Concurrency
- Streams
- Resource Management
- Observability
vào cùng một hệ thống thống nhất.
Nguồn:
- https://effect.website/
- https://dev.to/0012303/effect-ts-has-a-free-api-typescripts-missing-standard-library-for-production-apps-45k
Kết luận
Effect không phải thư viện dành cho mọi dự án.
Nếu ứng dụng của bạn chủ yếu là CRUD thông thường, chi phí học và áp dụng có thể lớn hơn lợi ích nhận được.
Nhưng nếu bạn đang xây:
- AI Agents
- Workflow Systems
- Event-driven Architecture
- Microservices
- Backend phức tạp với nhiều async operations
thì Effect là một trong những thư viện mạnh nhất hiện nay trong hệ sinh thái TypeScript.
Nó không chỉ giải quyết async programming, mà còn cố gắng cung cấp một mô hình nhất quán cho toàn bộ side effects trong ứng dụng.
Tài liệu tham khảo
Chính thức
Học Effect
- https://www.ayokoding.com/en/learn/software-engineering/platform-web/tools/ts-effect/by-example/overview/
- https://effect-ts-effect-smol.mintlify.app/
- https://www.mintlify.com/Effect-TS/effect-smol/reference/api-reference
Bài phân tích
All rights reserved