[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"header-categories":3,"post-error-handling-patterns-typescript":73,"parsed-post-34c5010b-6979-4dfa-8adc-32b1742c1101":147},{"success":4,"data":5},true,{"items":6,"pagination":70},[7,16,24,32,40,48,56,63],{"id":8,"name":9,"description":10,"parentId":11,"createdAt":12,"updatedAt":12,"parent":11,"children":13,"_count":14},"ai-future","AI & The Future","Artificial intelligence and emerging technology",null,"2026-07-24T06:02:45.990Z",[],{"posts":15},1,{"id":17,"name":18,"description":19,"parentId":11,"createdAt":20,"updatedAt":20,"parent":11,"children":21,"_count":22},"tools-productivity","Tools & Productivity","Developer tools and workflow optimization","2026-07-24T06:02:45.712Z",[],{"posts":23},7,{"id":25,"name":26,"description":27,"parentId":11,"createdAt":28,"updatedAt":28,"parent":11,"children":29,"_count":30},"career","Career & Growth","Professional development for developers","2026-07-24T06:02:45.486Z",[],{"posts":31},3,{"id":33,"name":34,"description":35,"parentId":11,"createdAt":36,"updatedAt":36,"parent":11,"children":37,"_count":38},"opinion","Opinion & Analysis","Industry analysis and technical opinions","2026-07-24T06:02:45.272Z",[],{"posts":39},6,{"id":41,"name":42,"description":43,"parentId":11,"createdAt":44,"updatedAt":44,"parent":11,"children":45,"_count":46},"tutorials","Tutorials","Step-by-step learning guides","2026-07-24T06:02:44.965Z",[],{"posts":47},21,{"id":49,"name":50,"description":51,"parentId":11,"createdAt":52,"updatedAt":52,"parent":11,"children":53,"_count":54},"software-engineering","Software Engineering","Best practices, patterns, and principles","2026-07-24T06:02:44.689Z",[],{"posts":55},24,{"id":57,"name":58,"description":59,"parentId":11,"createdAt":60,"updatedAt":60,"parent":11,"children":61,"_count":62},"devops-cloud","DevOps & Cloud","Infrastructure, deployment, and cloud computing","2026-07-24T06:02:44.453Z",[],{"posts":39},{"id":64,"name":65,"description":66,"parentId":11,"createdAt":67,"updatedAt":67,"parent":11,"children":68,"_count":69},"web-development","Web Development","Frontend and backend web development tutorials and guides","2026-07-24T06:02:44.169Z",[],{"posts":55},{"page":15,"limit":71,"total":71,"totalPages":15,"hasNext":72,"hasPrev":72},8,false,{"success":4,"data":74},{"id":75,"slug":76,"title":77,"excerpt":78,"content":79,"status":80,"visibility":81,"featuredImage":82,"canonicalUrl":11,"readingTime":83,"viewCount":84,"commentEnabled":4,"publishedAt":85,"scheduledAt":11,"createdAt":86,"updatedAt":87,"seoTitle":88,"seoDescription":78,"seoKeywords":11,"authorId":89,"author":90,"coAuthors":95,"tags":96,"categories":112,"comments":114,"_count":115,"relatedPosts":117},"34c5010b-6979-4dfa-8adc-32b1742c1101","error-handling-patterns-typescript","Error Handling Patterns in TypeScript Applications","Move beyond try-catch: Result types, error boundaries, and structured error handling that makes your TypeScript apps more resilient.","## The Problem with Try-Catch\n\nTry-catch is invisible in the type system. There's no way to know what errors a function might throw:\n\n```typescript\n\u002F\u002F What errors can this throw? No way to know from the signature.\nasync function getUser(id: string): Promise\u003CUser> {\n  const user = await db.user.findUnique({ where: { id } })\n  if (!user) throw new Error('Not found')\n  return user\n}\n```\n\n## The Result Pattern\n\nEncode success and failure in the return type:\n\n```typescript\ntype Result\u003CT, E = Error> =\n  | { ok: true; value: T }\n  | { ok: false; error: E }\n\nfunction ok\u003CT>(value: T): Result\u003CT, never> {\n  return { ok: true, value }\n}\n\nfunction err\u003CE>(error: E): Result\u003Cnever, E> {\n  return { ok: false, error }\n}\n```\n\nNow errors are visible in the type system:\n\n```typescript\ntype UserError = 'NOT_FOUND' | 'PERMISSION_DENIED'\n\nasync function getUser(id: string): Promise\u003CResult\u003CUser, UserError>> {\n  const user = await db.user.findUnique({ where: { id } })\n  if (!user) return err('NOT_FOUND')\n  return ok(user)\n}\n\n\u002F\u002F Caller MUST handle both cases\nconst result = await getUser('123')\nif (!result.ok) {\n  \u002F\u002F result.error is typed as UserError\n  switch (result.error) {\n    case 'NOT_FOUND': return notFound()\n    case 'PERMISSION_DENIED': return forbidden()\n  }\n}\n\u002F\u002F result.value is typed as User\nconsole.log(result.value.name)\n```\n\n::callout{icon=\"i-lucide-shield-check\" color=\"success\"}\nThe Result pattern forces callers to handle errors. No more uncaught exceptions crashing your app at 3am.\n::\n\n## Custom Error Classes\n\n```typescript\nclass AppError extends Error {\n  constructor(\n    message: string,\n    public code: string,\n    public statusCode: number = 500,\n    public details?: unknown,\n  ) {\n    super(message)\n    this.name = 'AppError'\n  }\n\n  static notFound(resource: string) {\n    return new AppError(`${resource} not found`, 'NOT_FOUND', 404)\n  }\n\n  static validation(details: Record\u003Cstring, string>) {\n    return new AppError('Validation failed', 'VALIDATION', 422, details)\n  }\n\n  static unauthorized() {\n    return new AppError('Unauthorized', 'UNAUTHORIZED', 401)\n  }\n}\n```\n\n## Global Error Handler (Nuxt)\n\n```typescript\n\u002F\u002F server\u002Fmiddleware\u002Ferror-handler.ts\nexport default defineEventHandler((event) => {\n  event.node.res.on('error', (error) => {\n    if (error instanceof AppError) {\n      sendError(event, createError({\n        statusCode: error.statusCode,\n        message: error.message,\n        data: { code: error.code, details: error.details },\n      }))\n    }\n  })\n})\n```\n\n## Wrapping External Libraries\n\n```typescript\n\u002F\u002F Wrap fetch to return Results\nasync function safeFetch\u003CT>(url: string): Promise\u003CResult\u003CT, FetchError>> {\n  try {\n    const response = await fetch(url)\n    if (!response.ok) {\n      return err({ type: 'HTTP_ERROR', status: response.status })\n    }\n    const data = await response.json()\n    return ok(data as T)\n  } catch (e) {\n    return err({ type: 'NETWORK_ERROR', message: (e as Error).message })\n  }\n}\n```\n\n## Summary\n\n- Use **Result types** for expected failures (validation, not found)\n- Use **exceptions** for unexpected failures (DB connection lost)\n- Use **custom error classes** for structured error information\n- **Handle errors at the boundary** — don't let them propagate silently\n","published","public","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1559028012-481c04fa702d?w=1200&q=80",9,520,"2026-06-03T06:03:46.537Z","2026-07-24T06:03:46.540Z","2026-07-28T17:09:00.145Z","Error Handling Patterns in TypeScript Applications | BitBlog","fddb5d93-7a2c-4d86-a06a-fa32e73a01c6",{"email":91,"bio":92,"id":89,"name":93,"avatarUrl":94},"mbeahessilfieprince@gmail.com","Fullstack Software Developer ","Mbeah Essilfie","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F93322394?v=4",[],[97,102,107],{"id":98,"name":99,"color":100,"description":101},"typescript","TypeScript","#3178c6","Typed superset of JavaScript",{"id":103,"name":104,"color":105,"description":106},"nodejs","Node.js","#339933","JavaScript runtime built on V8",{"id":108,"name":109,"color":110,"description":111},"architecture","Architecture","#795548","Software architecture patterns",[113],{"id":49,"name":50,"description":51},[],{"comments":116},0,[118,127,137],{"id":119,"slug":120,"title":121,"excerpt":122,"featuredImage":123,"viewCount":124,"readingTime":71,"publishedAt":125,"author":126},"2997028f-4d22-4eb7-9d86-894a54cb559a","building-type-safe-apis-nuxt3-prisma","Building Type-Safe APIs with Nuxt 3 and Prisma","Learn how to build end-to-end type-safe APIs using Nuxt 3 server routes and Prisma ORM for a seamless developer experience.","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1498050108023-c5249f4df085?w=1200&q=80",1922,"2026-07-23T06:02:46.910Z",{"id":89,"name":93,"avatarUrl":94},{"id":128,"slug":129,"title":130,"excerpt":131,"featuredImage":132,"viewCount":133,"readingTime":134,"publishedAt":135,"author":136},"da9e4553-8b0d-411e-b4ec-f9684017e163","mastering-tailwind-css-design-systems","Mastering Tailwind CSS: From Utility Classes to Design Systems","Go beyond basic utility classes and learn how to build cohesive, maintainable design systems with Tailwind CSS.","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1555066931-4365d14bab8c?w=1200&q=80",257,10,"2026-07-21T06:02:49.268Z",{"id":89,"name":93,"avatarUrl":94},{"id":138,"slug":139,"title":140,"excerpt":141,"featuredImage":142,"viewCount":143,"readingTime":144,"publishedAt":145,"author":146},"50add5fc-4026-4267-b917-7f71ea9e35b0","complete-guide-vue3-composables","The Complete Guide to Vue 3 Composables","Understand the power of Vue 3's Composition API through practical, real-world composable patterns that you can use today.","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1517694712202-14dd9538aa97?w=1200&q=80",990,12,"2026-07-19T06:02:51.753Z",{"id":89,"name":93,"avatarUrl":94},{"data":148,"body":150,"toc":326},{"title":149,"description":149},"",{"type":151,"children":152},"root",[153,162,168,180,186,191,199,204,212,223,229,237,243,251,257,265,271,321],{"type":154,"tag":155,"props":156,"children":158},"element","h2",{"id":157},"the-problem-with-try-catch",[159],{"type":160,"value":161},"text","The Problem with Try-Catch",{"type":154,"tag":163,"props":164,"children":165},"p",{},[166],{"type":160,"value":167},"Try-catch is invisible in the type system. There's no way to know what errors a function might throw:",{"type":154,"tag":169,"props":170,"children":174},"pre",{"className":171,"code":172,"language":98,"meta":149,"style":173},"language-typescript","\u002F\u002F What errors can this throw? No way to know from the signature.\nasync function getUser(id: string): Promise\u003CUser> {\n  const user = await db.user.findUnique({ where: { id } })\n  if (!user) throw new Error('Not found')\n  return user\n}\n","undefined",[175],{"type":154,"tag":176,"props":177,"children":178},"code",{"__ignoreMap":149},[179],{"type":160,"value":172},{"type":154,"tag":155,"props":181,"children":183},{"id":182},"the-result-pattern",[184],{"type":160,"value":185},"The Result Pattern",{"type":154,"tag":163,"props":187,"children":188},{},[189],{"type":160,"value":190},"Encode success and failure in the return type:",{"type":154,"tag":169,"props":192,"children":194},{"className":171,"code":193,"language":98,"meta":149,"style":173},"type Result\u003CT, E = Error> =\n  | { ok: true; value: T }\n  | { ok: false; error: E }\n\nfunction ok\u003CT>(value: T): Result\u003CT, never> {\n  return { ok: true, value }\n}\n\nfunction err\u003CE>(error: E): Result\u003Cnever, E> {\n  return { ok: false, error }\n}\n",[195],{"type":154,"tag":176,"props":196,"children":197},{"__ignoreMap":149},[198],{"type":160,"value":193},{"type":154,"tag":163,"props":200,"children":201},{},[202],{"type":160,"value":203},"Now errors are visible in the type system:",{"type":154,"tag":169,"props":205,"children":207},{"className":171,"code":206,"language":98,"meta":149,"style":173},"type UserError = 'NOT_FOUND' | 'PERMISSION_DENIED'\n\nasync function getUser(id: string): Promise\u003CResult\u003CUser, UserError>> {\n  const user = await db.user.findUnique({ where: { id } })\n  if (!user) return err('NOT_FOUND')\n  return ok(user)\n}\n\n\u002F\u002F Caller MUST handle both cases\nconst result = await getUser('123')\nif (!result.ok) {\n  \u002F\u002F result.error is typed as UserError\n  switch (result.error) {\n    case 'NOT_FOUND': return notFound()\n    case 'PERMISSION_DENIED': return forbidden()\n  }\n}\n\u002F\u002F result.value is typed as User\nconsole.log(result.value.name)\n",[208],{"type":154,"tag":176,"props":209,"children":210},{"__ignoreMap":149},[211],{"type":160,"value":206},{"type":154,"tag":213,"props":214,"children":217},"callout",{"color":215,"icon":216},"success","i-lucide-shield-check",[218],{"type":154,"tag":163,"props":219,"children":220},{},[221],{"type":160,"value":222},"The Result pattern forces callers to handle errors. No more uncaught exceptions crashing your app at 3am.",{"type":154,"tag":155,"props":224,"children":226},{"id":225},"custom-error-classes",[227],{"type":160,"value":228},"Custom Error Classes",{"type":154,"tag":169,"props":230,"children":232},{"className":171,"code":231,"language":98,"meta":149,"style":173},"class AppError extends Error {\n  constructor(\n    message: string,\n    public code: string,\n    public statusCode: number = 500,\n    public details?: unknown,\n  ) {\n    super(message)\n    this.name = 'AppError'\n  }\n\n  static notFound(resource: string) {\n    return new AppError(`${resource} not found`, 'NOT_FOUND', 404)\n  }\n\n  static validation(details: Record\u003Cstring, string>) {\n    return new AppError('Validation failed', 'VALIDATION', 422, details)\n  }\n\n  static unauthorized() {\n    return new AppError('Unauthorized', 'UNAUTHORIZED', 401)\n  }\n}\n",[233],{"type":154,"tag":176,"props":234,"children":235},{"__ignoreMap":149},[236],{"type":160,"value":231},{"type":154,"tag":155,"props":238,"children":240},{"id":239},"global-error-handler-nuxt",[241],{"type":160,"value":242},"Global Error Handler (Nuxt)",{"type":154,"tag":169,"props":244,"children":246},{"className":171,"code":245,"language":98,"meta":149,"style":173},"\u002F\u002F server\u002Fmiddleware\u002Ferror-handler.ts\nexport default defineEventHandler((event) => {\n  event.node.res.on('error', (error) => {\n    if (error instanceof AppError) {\n      sendError(event, createError({\n        statusCode: error.statusCode,\n        message: error.message,\n        data: { code: error.code, details: error.details },\n      }))\n    }\n  })\n})\n",[247],{"type":154,"tag":176,"props":248,"children":249},{"__ignoreMap":149},[250],{"type":160,"value":245},{"type":154,"tag":155,"props":252,"children":254},{"id":253},"wrapping-external-libraries",[255],{"type":160,"value":256},"Wrapping External Libraries",{"type":154,"tag":169,"props":258,"children":260},{"className":171,"code":259,"language":98,"meta":149,"style":173},"\u002F\u002F Wrap fetch to return Results\nasync function safeFetch\u003CT>(url: string): Promise\u003CResult\u003CT, FetchError>> {\n  try {\n    const response = await fetch(url)\n    if (!response.ok) {\n      return err({ type: 'HTTP_ERROR', status: response.status })\n    }\n    const data = await response.json()\n    return ok(data as T)\n  } catch (e) {\n    return err({ type: 'NETWORK_ERROR', message: (e as Error).message })\n  }\n}\n",[261],{"type":154,"tag":176,"props":262,"children":263},{"__ignoreMap":149},[264],{"type":160,"value":259},{"type":154,"tag":155,"props":266,"children":268},{"id":267},"summary",[269],{"type":160,"value":270},"Summary",{"type":154,"tag":272,"props":273,"children":274},"ul",{},[275,289,300,311],{"type":154,"tag":276,"props":277,"children":278},"li",{},[279,281,287],{"type":160,"value":280},"Use ",{"type":154,"tag":282,"props":283,"children":284},"strong",{},[285],{"type":160,"value":286},"Result types",{"type":160,"value":288}," for expected failures (validation, not found)",{"type":154,"tag":276,"props":290,"children":291},{},[292,293,298],{"type":160,"value":280},{"type":154,"tag":282,"props":294,"children":295},{},[296],{"type":160,"value":297},"exceptions",{"type":160,"value":299}," for unexpected failures (DB connection lost)",{"type":154,"tag":276,"props":301,"children":302},{},[303,304,309],{"type":160,"value":280},{"type":154,"tag":282,"props":305,"children":306},{},[307],{"type":160,"value":308},"custom error classes",{"type":160,"value":310}," for structured error information",{"type":154,"tag":276,"props":312,"children":313},{},[314,319],{"type":154,"tag":282,"props":315,"children":316},{},[317],{"type":160,"value":318},"Handle errors at the boundary",{"type":160,"value":320}," — don't let them propagate silently",{"type":154,"tag":322,"props":323,"children":324},"style",{},[325],{"type":160,"value":149},{"title":149,"searchDepth":327,"depth":327,"links":328},2,[329,330,331,332,333,334],{"id":157,"depth":327,"text":161},{"id":182,"depth":327,"text":185},{"id":225,"depth":327,"text":228},{"id":239,"depth":327,"text":242},{"id":253,"depth":327,"text":256},{"id":267,"depth":327,"text":270}]