[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"header-categories":3,"post-clean-maintainable-typescript-patterns":73,"parsed-post-036672b9-426d-4b45-8b7d-c71bf6a20768":142},{"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":107,"comments":109,"_count":110,"relatedPosts":112},"036672b9-426d-4b45-8b7d-c71bf6a20768","clean-maintainable-typescript-patterns","Writing Clean, Maintainable TypeScript: Patterns I Use Daily","Practical TypeScript patterns for real codebases — discriminated unions, branded types, builder patterns, and more.","## TypeScript Is More Than \"JavaScript With Types\"\n\nMost developers use TypeScript as a type-annotation layer. But its type system is powerful enough to encode business rules, eliminate impossible states, and guide developers toward correct code.\n\n## Discriminated Unions\n\n```typescript\n\u002F\u002F Instead of optional fields that lead to impossible states:\ntype Result\u003CT> =\n  | { status: 'success'; data: T }\n  | { status: 'error'; error: Error }\n  | { status: 'loading' }\n\nfunction handleResult(result: Result\u003CUser>) {\n  switch (result.status) {\n    case 'success':\n      \u002F\u002F TypeScript knows result.data exists here\n      console.log(result.data.name)\n      break\n    case 'error':\n      \u002F\u002F TypeScript knows result.error exists here\n      console.error(result.error.message)\n      break\n    case 'loading':\n      \u002F\u002F No data or error accessible\n      break\n  }\n}\n```\n\n## Branded Types\n\nPrevent mixing up values that share the same primitive type:\n\n```typescript\ntype UserId = string & { __brand: 'UserId' }\ntype PostId = string & { __brand: 'PostId' }\n\nfunction createUserId(id: string): UserId {\n  return id as UserId\n}\n\nfunction getPost(postId: PostId) { \u002F* ... *\u002F }\n\nconst userId = createUserId('abc-123')\n\u002F\u002F getPost(userId) \u002F\u002F ❌ Type error! Can't pass UserId as PostId\n```\n\n::callout{icon=\"i-lucide-shield\" color=\"primary\"}\nBranded types add zero runtime cost. They exist purely at compile time but prevent an entire class of ID-mixup bugs.\n::\n\n## The Builder Pattern\n\n```typescript\nclass QueryBuilder\u003CT> {\n  private filters: Record\u003Cstring, unknown> = {}\n  private sortField?: keyof T\n  private limitValue?: number\n\n  where\u003CK extends keyof T>(field: K, value: T[K]): this {\n    this.filters[field as string] = value\n    return this\n  }\n\n  orderBy(field: keyof T): this {\n    this.sortField = field\n    return this\n  }\n\n  limit(n: number): this {\n    this.limitValue = n\n    return this\n  }\n\n  build() {\n    return { filters: this.filters, sort: this.sortField, limit: this.limitValue }\n  }\n}\n\n\u002F\u002F Usage - fully typed!\nconst query = new QueryBuilder\u003CPost>()\n  .where('status', 'published')\n  .orderBy('publishedAt')\n  .limit(10)\n  .build()\n```\n\n## Exhaustive Checks\n\n```typescript\nfunction assertNever(x: never): never {\n  throw new Error(`Unexpected value: ${x}`)\n}\n\ntype Theme = 'light' | 'dark' | 'system'\n\nfunction getBackground(theme: Theme): string {\n  switch (theme) {\n    case 'light': return '#ffffff'\n    case 'dark': return '#1a1a1a'\n    case 'system': return 'var(--bg)'\n    default: return assertNever(theme) \u002F\u002F Compile error if you miss a case\n  }\n}\n```\n\n## Summary\n\nGood TypeScript makes invalid states unrepresentable. Use the type system as documentation that the compiler enforces.\n","published","public","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1587620962725-abab7fe55159?w=1200&q=80",9,1173,"2026-07-11T06:03:01.475Z","2026-07-24T06:03:01.478Z","2026-07-28T17:09:40.856Z","Writing Clean, Maintainable TypeScript: Patterns I Use Daily | 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],{"id":98,"name":99,"color":100,"description":101},"typescript","TypeScript","#3178c6","Typed superset of JavaScript",{"id":103,"name":104,"color":105,"description":106},"architecture","Architecture","#795548","Software architecture patterns",[108],{"id":49,"name":50,"description":51},[],{"comments":111},0,[113,122,132],{"id":114,"slug":115,"title":116,"excerpt":117,"featuredImage":118,"viewCount":119,"readingTime":71,"publishedAt":120,"author":121},"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":123,"slug":124,"title":125,"excerpt":126,"featuredImage":127,"viewCount":128,"readingTime":129,"publishedAt":130,"author":131},"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":133,"slug":134,"title":135,"excerpt":136,"featuredImage":137,"viewCount":138,"readingTime":139,"publishedAt":140,"author":141},"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":143,"body":145,"toc":255},{"title":144,"description":144},"",{"type":146,"children":147},"root",[148,157,163,169,181,187,192,200,211,217,225,231,239,245,250],{"type":149,"tag":150,"props":151,"children":153},"element","h2",{"id":152},"typescript-is-more-than-javascript-with-types",[154],{"type":155,"value":156},"text","TypeScript Is More Than \"JavaScript With Types\"",{"type":149,"tag":158,"props":159,"children":160},"p",{},[161],{"type":155,"value":162},"Most developers use TypeScript as a type-annotation layer. But its type system is powerful enough to encode business rules, eliminate impossible states, and guide developers toward correct code.",{"type":149,"tag":150,"props":164,"children":166},{"id":165},"discriminated-unions",[167],{"type":155,"value":168},"Discriminated Unions",{"type":149,"tag":170,"props":171,"children":175},"pre",{"className":172,"code":173,"language":98,"meta":144,"style":174},"language-typescript","\u002F\u002F Instead of optional fields that lead to impossible states:\ntype Result\u003CT> =\n  | { status: 'success'; data: T }\n  | { status: 'error'; error: Error }\n  | { status: 'loading' }\n\nfunction handleResult(result: Result\u003CUser>) {\n  switch (result.status) {\n    case 'success':\n      \u002F\u002F TypeScript knows result.data exists here\n      console.log(result.data.name)\n      break\n    case 'error':\n      \u002F\u002F TypeScript knows result.error exists here\n      console.error(result.error.message)\n      break\n    case 'loading':\n      \u002F\u002F No data or error accessible\n      break\n  }\n}\n","undefined",[176],{"type":149,"tag":177,"props":178,"children":179},"code",{"__ignoreMap":144},[180],{"type":155,"value":173},{"type":149,"tag":150,"props":182,"children":184},{"id":183},"branded-types",[185],{"type":155,"value":186},"Branded Types",{"type":149,"tag":158,"props":188,"children":189},{},[190],{"type":155,"value":191},"Prevent mixing up values that share the same primitive type:",{"type":149,"tag":170,"props":193,"children":195},{"className":172,"code":194,"language":98,"meta":144,"style":174},"type UserId = string & { __brand: 'UserId' }\ntype PostId = string & { __brand: 'PostId' }\n\nfunction createUserId(id: string): UserId {\n  return id as UserId\n}\n\nfunction getPost(postId: PostId) { \u002F* ... *\u002F }\n\nconst userId = createUserId('abc-123')\n\u002F\u002F getPost(userId) \u002F\u002F ❌ Type error! Can't pass UserId as PostId\n",[196],{"type":149,"tag":177,"props":197,"children":198},{"__ignoreMap":144},[199],{"type":155,"value":194},{"type":149,"tag":201,"props":202,"children":205},"callout",{"color":203,"icon":204},"primary","i-lucide-shield",[206],{"type":149,"tag":158,"props":207,"children":208},{},[209],{"type":155,"value":210},"Branded types add zero runtime cost. They exist purely at compile time but prevent an entire class of ID-mixup bugs.",{"type":149,"tag":150,"props":212,"children":214},{"id":213},"the-builder-pattern",[215],{"type":155,"value":216},"The Builder Pattern",{"type":149,"tag":170,"props":218,"children":220},{"className":172,"code":219,"language":98,"meta":144,"style":174},"class QueryBuilder\u003CT> {\n  private filters: Record\u003Cstring, unknown> = {}\n  private sortField?: keyof T\n  private limitValue?: number\n\n  where\u003CK extends keyof T>(field: K, value: T[K]): this {\n    this.filters[field as string] = value\n    return this\n  }\n\n  orderBy(field: keyof T): this {\n    this.sortField = field\n    return this\n  }\n\n  limit(n: number): this {\n    this.limitValue = n\n    return this\n  }\n\n  build() {\n    return { filters: this.filters, sort: this.sortField, limit: this.limitValue }\n  }\n}\n\n\u002F\u002F Usage - fully typed!\nconst query = new QueryBuilder\u003CPost>()\n  .where('status', 'published')\n  .orderBy('publishedAt')\n  .limit(10)\n  .build()\n",[221],{"type":149,"tag":177,"props":222,"children":223},{"__ignoreMap":144},[224],{"type":155,"value":219},{"type":149,"tag":150,"props":226,"children":228},{"id":227},"exhaustive-checks",[229],{"type":155,"value":230},"Exhaustive Checks",{"type":149,"tag":170,"props":232,"children":234},{"className":172,"code":233,"language":98,"meta":144,"style":174},"function assertNever(x: never): never {\n  throw new Error(`Unexpected value: ${x}`)\n}\n\ntype Theme = 'light' | 'dark' | 'system'\n\nfunction getBackground(theme: Theme): string {\n  switch (theme) {\n    case 'light': return '#ffffff'\n    case 'dark': return '#1a1a1a'\n    case 'system': return 'var(--bg)'\n    default: return assertNever(theme) \u002F\u002F Compile error if you miss a case\n  }\n}\n",[235],{"type":149,"tag":177,"props":236,"children":237},{"__ignoreMap":144},[238],{"type":155,"value":233},{"type":149,"tag":150,"props":240,"children":242},{"id":241},"summary",[243],{"type":155,"value":244},"Summary",{"type":149,"tag":158,"props":246,"children":247},{},[248],{"type":155,"value":249},"Good TypeScript makes invalid states unrepresentable. Use the type system as documentation that the compiler enforces.",{"type":149,"tag":251,"props":252,"children":253},"style",{},[254],{"type":155,"value":144},{"title":144,"searchDepth":256,"depth":256,"links":257},2,[258,259,260,261,262,263],{"id":152,"depth":256,"text":156},{"id":165,"depth":256,"text":168},{"id":183,"depth":256,"text":186},{"id":213,"depth":256,"text":216},{"id":227,"depth":256,"text":230},{"id":241,"depth":256,"text":244}]