Most TypeScript devs reach for "any" when types get complex. There's a cleaner fix: discriminated unions. Instead of a type with optional fields (data, error, loading) that might all be undefined at the same time, you model each state explicitly with a shared "status" field. Something like: - { status: 'loading' } - { status: 'error', error: string } - { status: 'success', data: User } Now TypeScript knows exactly what's available in each branch. No more optional chaining and null fallbacks everywhere. Your switch statements get exhaustiveness checking for free. This pattern shines in React. When your component renders based on fetch status, each arm of the union is a compiler-enforced contract. You cannot accidentally access data while in an error state. I use this constantly in B2B SaaS apps where complex async flows are the norm. It cuts runtime surprises significantly. Bonus tip: add a never exhaustiveness check in your switch default and you'll catch missing cases at compile time, not in production. What is your go-to TypeScript pattern for managing complex async state? #TypeScript #React #WebDevelopment
Radu Catalin-Andrei’s Post
More Relevant Posts
-
Most React devs manage async state with 3 separate variables: loading, data, error. Three flags that can contradict each other. Ever seen loading = false, data = null, and error = null all at once? What does that even mean? TypeScript discriminated unions fix this cleanly: type State = | { status: 'idle' } | { status: 'loading' } | { status: 'success'; data: User[] } | { status: 'error'; error: string } Now states are mutually exclusive. When status is 'success', TypeScript knows data exists. When it's 'error', it knows error exists. No more optional chaining everywhere. No more "can this even be null here?" in code review. Your render logic becomes a simple switch statement, and entire categories of bugs get caught at compile time instead of at 2am in production. I've been using this pattern in B2B SaaS dashboards for years. It's one of those things I genuinely wish I adopted sooner. What patterns are you using to manage async state in React? #TypeScript #React
To view or add a comment, sign in
-
Most React devs handle API state like this: isLoading, isError, data, three separate booleans that can contradict each other. Loading = true AND error = true at the same time? Shouldn't happen, but nothing prevents it. Discriminated unions fix this cleanly: type AsyncState<T> = | { status: 'idle' } | { status: 'loading' } | { status: 'success'; data: T } | { status: 'error'; error: Error } Now TypeScript enforces that you handle each case. Inside the 'success' branch, state.data is always defined. No optional chaining, no null checks. The real win: when you switch on state.status, TypeScript narrows automatically. No more wondering "is data null because it's loading, or because it failed?" It's a small change that eliminates a whole class of bugs and makes component logic self-documenting. What state patterns are you reaching for in your React projects right now? #TypeScript #React #WebDevelopment
To view or add a comment, sign in
-
Most TypeScript devs use union types. Not enough use discriminated unions. The difference is massive. A plain union gives TypeScript no way to narrow between branches automatically. You end up writing guard functions or casting types, hoping you got it right. A discriminated union adds a shared literal field, like status: 'success' | 'error' | 'loading'. Now TypeScript narrows automatically in every if/switch. Forget a case? Compile error. Add a new state? Every component that handles it gets flagged. I've used this pattern on every B2B SaaS project for the past 3 years: async data fetching, form state, multi-step flows. It eliminates entire categories of bugs before they reach production. The real payoff is not the compiler checks. It's that you're forced to model all possible states up front. That discipline changes how you think about component design. If you build anything with more than two possible states in React, try modeling it as a discriminated union first. What patterns do you use to make impossible states actually impossible? #TypeScript #React
To view or add a comment, sign in
-
My API was fine locally. In production, it started slowing down randomly. No bugs. No crashes. Just slow. . . What was happening: A simple API endpoint was doing this: fetching data looping over it making extra async calls inside the loop Locally: fine. Production: request time kept creeping up under load. The mistake: Not understanding what happens when you mix loops + async calls. People assume this runs “one after another, but async”. It doesn’t. It triggers multiple concurrent operations without control, and suddenly your DB, APIs, or external services are getting hit way harder than expected. Fix (simple version): Instead of uncontrolled async inside loops: limit concurrency (batch or queue) or restructure with proper aggregation or use { Promise.all } only when you actually want parallel load Result: Same logic. Predictable performance. No more “it works on my machine” confidence. Node.js doesn’t usually fail loudly. It just slowly gets tired because you asked it to do everything at once. #NodeJS #BackendDevelopment #WebDevelopment #JavaScript #SystemDesign #SoftwareEngineering #BackendEngineering #PerformanceOptimization #Scalability #TechDebate
To view or add a comment, sign in
-
-
Choosing the right validation approach in Node.js can make a big difference. Here’s a quick comparison I found useful 👇 🟠 Joi (Schema-based) ✔ Define validation schema ✔ Validate entire data object ✔ Clean and reusable Best for: structured and scalable applications 🟢 express-validator (Middleware-based) ✔ Works directly in Express routes ✔ Validates request step-by-step ✔ Easy to use for small APIs Best for: quick and simple validation ⚔️ Key difference: Joi → define rules for data structure express-validator → validate request during handling ❓ Quick FAQ 👉 Which one should I use? Depends on project complexity. 👉 Can I use both? Yes, but usually one is enough. 👉 Why is validation important? Prevents invalid data and improves API security. Backend development is not just about handling requests — it’s about handling them correctly. #NodeJS #BackendDeveloper #Validation #WebDevelopment
To view or add a comment, sign in
-
-
Most React state bugs I've debugged come down to one thing: impossible states. You've probably seen this pattern: const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState(null) const [data, setData] = useState(null) The problem? All three can be true at the same time. isLoading: true with data: {...} is technically valid TypeScript. That's a silent bug. The fix: model your state as a discriminated union. type FetchState = | { status: 'idle' } | { status: 'loading' } | { status: 'error'; error: string } | { status: 'success'; data: YourData } Now impossible states literally cannot exist. TypeScript won't let them compile. In B2B SaaS dashboards I've worked on, this pattern eliminated whole categories of "loading but also showing stale data" bugs that were painful to reproduce. Bonus: it's self-documenting. Any engineer reading it immediately knows every state the component can be in. What's your go-to pattern for managing async state in React? #TypeScript #React #Frontend
To view or add a comment, sign in
-
Your frontend and your backend are speaking two different languages. And it's costing you hours of debugging every single week. Stop "hoping" your API data is correct. In most Next.js projects, we treat the backend response like a promise that never breaks. We define an interface, fetch the data, and pray the schema hasn't changed. Then production happens. • A field name changes. • A required string becomes null. • A number becomes a string. Your UI crashes, your logs blow up, and you spend 3 hours hunting for a "Type Error" that TypeScript couldn't catch at build time. The "Senior" Architecture: 1. Zero Trust Policy: Never assume the API is right. 2. Schema Validation: Use Zod to parse every single incoming payload. 3. Fail Gracefully: If the data is wrong, handle it at the boundary—don't let it poison your entire component tree. The Reality: Type-safety is a lie if it only exists in your IDE. If your data isn't validated at runtime, your "Senior" title is just a label. Are you still manually checking if data?.user?.profile exists, or are you actually validating your engine? 👇 #NextJS #TypeScript #CleanCode #SoftwareArchitecture #FullStackDevelopment #SaaS #WebDev
To view or add a comment, sign in
-
-
Node.js developers, ever hit a memory wall when handling large files or processing extensive datasets? If you're buffering entire files into memory before processing them, you might be overlooking one of Node.js's most powerful features: the Stream API. Instead of loading a multi-gigabyte file into RAM (which can quickly exhaust server resources), `fs.createReadStream()` and `fs.createWriteStream()` enable you to process data in small, manageable chunks. This elegant approach allows you to pipe data directly from source to destination, drastically reducing memory footprint and improving application responsiveness. It's a true game-changer for I/O-intensive tasks like real-time log aggregation, video transcoding, or large CSV imports. Building scalable and robust applications relies heavily on efficient resource management, and Streams are a cornerstone of that in Node.js. What are some creative ways you've leveraged Node.js Streams to optimize your applications and avoid memory bottlenecks? Share your insights! #Nodejs #BackendDevelopment #WebDevelopment #PerformanceOptimization #JavaScript #StreamsAPI #DeveloperTips References: Node.js Stream API Documentation - https://lnkd.in/geSRS4_u Working with streams in Node.js: A complete guide - https://lnkd.in/gZjN7eG8
To view or add a comment, sign in
-
Most backend developers write CRUD logic multiple times… I used to do the same. Until I fixed it in my Natours API. Instead of repeating Create, Read, Update, Delete logic across controllers (Tours, Users, Reviews), I implemented the Factory Functions Pattern. Now, instead of writing full controllers, I simply do: export const deleteTour = factory.deleteOne(Tour); The result? ✅ DRY Code: No more "Copy-Paste" logic across different controllers. ✅ Scalability: Adding a new resource now takes minutes, not hours. ✅ Maintainability: If I need to change how data is updated, I change it in one place, and it reflects everywhere. It's about working smarter, not harder. Check out the Factory implementation here: [https://lnkd.in/dUgc3hVs] #NodeJS #Backend #CleanCode #SoftwareArchitecture #DesignPatterns #ExpressJS
To view or add a comment, sign in
-
-
A good backend should be: ✅ Scalable ✅ Secure ✅ Easy to maintain ✅ Well-structured ✅ Fast and reliable One thing I always focus on is clean architecture. Separating routes, controllers, services, and database logic makes the codebase easier to understand and improve. In backend development, small decisions matter a lot — error handling, validation, authentication, logging, and database design can make or break an application. Node.js is powerful, but using it well requires discipline, structure, and continuous learning. What is one backend practice you always follow? #NodeJS #BackendDevelopment #SoftwareEngineering #JavaScript #APIDevelopment
To view or add a comment, sign in
-
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development