[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"playground-weekly-typescript-generics":3,"verticals":17},{"slug":4,"title":5,"summary":6,"html":7,"css":8,"js":9,"config":10,"doc":13},"weekly-typescript-generics","TypeScript Generics: any vs &lt;T&gt;",null,"\u003Cdiv class=\"wrap\">\n    \u003Ch1>🎮 TypeScript generics — \u003Ccode>any\u003C\u002Fcode> vs \u003Ccode>&lt;T&gt;\u003C\u002Fcode>\u003C\u002Fh1>\n    \u003Cp class=\"sub\">\n      Pick a dataset, then click \"Call \u003Ccode>.toUpperCase()\u003C\u002Fcode> on the first item.\"\n      Both cards run the \u003Cem>same\u003C\u002Fem> operation on the \u003Cem>same\u003C\u002Fem> data — one typed\n      \u003Ccode>any\u003C\u002Fcode>, one typed generically. Watch what each one catches, and when.\n    \u003C\u002Fp>\n\n    \u003Cdiv class=\"presets\">\n      \u003Cbutton data-set=\"numbers\" class=\"active\">Numbers: [1, 2, 3]\u003C\u002Fbutton>\n      \u003Cbutton data-set=\"strings\">Strings: [\"ada\", \"grace\"]\u003C\u002Fbutton>\n      \u003Cbutton data-set=\"objects\">Objects: [{ id: 1 }]\u003C\u002Fbutton>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"cards\">\n      \u003Cdiv class=\"card\">\n        \u003Ch2>any version\u003C\u002Fh2>\n        \u003Cpre>\u003Ccode>function firstElement(arr: any): any {\n  return arr[0];\n}\u003C\u002Fcode>\u003C\u002Fpre>\n        \u003Cdiv class=\"result idle\" id=\"anyResult\">Pick a preset, then hit run.\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"card\">\n        \u003Ch2>&lt;T&gt; version\u003C\u002Fh2>\n        \u003Cpre>\u003Ccode>function firstElement&lt;T&gt;(arr: T[]): T | undefined {\n  return arr[0];\n}\u003C\u002Fcode>\u003C\u002Fpre>\n        \u003Cdiv class=\"result idle\" id=\"genResult\">Pick a preset, then hit run.\u003C\u002Fdiv>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv class=\"actions\">\n      \u003Cbutton class=\"primary\" id=\"run\">Call .toUpperCase() on the first item\u003C\u002Fbutton>\n      \u003Cbutton class=\"ghost\" id=\"reset\">Reset\u003C\u002Fbutton>\n    \u003C\u002Fdiv>\n\n    \u003Cp class=\"note\" id=\"explainer\">\n      \u003Cstrong>What just happened:\u003C\u002Fstrong> pick a preset and press run to find out.\n    \u003C\u002Fp>\n  \u003C\u002Fdiv>",":root {\n    --bg: #0f1115; --panel: #171a21; --ink: #e8ebf2; --muted: #99a1b3;\n    --accent: #6ea8fe; --good: #3fb950; --bad: #f85149; --line: #262b36;\n    font-family: ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n  }\n  * { box-sizing: border-box; }\n  body { margin: 0; background: var(--bg); color: var(--ink); min-height: 100vh; padding: 20px; }\n  .wrap { width: 100%; max-width: 760px; margin: 0 auto; }\n  h1 { font-size: 1.2rem; margin: 0 0 2px; }\n  .sub { color: var(--muted); font-size: .88rem; margin: 0 0 16px; line-height: 1.4; }\n  .presets { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }\n  .presets button { font: inherit; font-size: .82rem; font-weight: 600; color: var(--ink);\n    background: transparent; border: 1px solid var(--line); border-radius: 999px;\n    padding: 6px 12px; cursor: pointer; }\n  .presets button.active { background: var(--accent); color: #0b0d10; border-color: var(--accent); }\n  .presets button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }\n  .cards { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }\n  @media (max-width: 560px) { .cards { grid-template-columns: 1fr; } }\n  .card { background: var(--panel); border: 1px solid var(--line); border-radius: 14px; padding: 14px; }\n  .card h2 { font-size: .85rem; margin: 0 0 8px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }\n  .card pre { background: #0b0d10; border-radius: 8px; padding: 10px; margin: 0 0 10px;\n    font-size: .78rem; overflow-x: auto; line-height: 1.5; }\n  .card pre code { color: var(--ink); }\n  .result { min-height: 46px; font-size: .85rem; border-top: 1px dashed var(--line);\n    padding-top: 10px; font-variant-numeric: tabular-nums; }\n  .result b { display: block; margin-bottom: 4px; }\n  .ok { color: var(--good); }\n  .fail { color: var(--bad); }\n  .idle { color: var(--muted); }\n  .actions { display: flex; gap: 10px; margin: 16px 0; flex-wrap: wrap; }\n  button.primary { font: inherit; font-weight: 700; color: #0b0d10; background: var(--accent);\n    border: 0; border-radius: 10px; padding: 10px 16px; cursor: pointer; }\n  button.ghost { font: inherit; font-weight: 600; color: var(--ink); background: transparent;\n    border: 1px solid var(--line); border-radius: 10px; padding: 10px 16px; cursor: pointer; }\n  button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }\n  .note { font-size: .78rem; color: var(--muted); margin-top: 14px; line-height: 1.5; }","const $ = (id) => document.getElementById(id);\n  const anyResult = $(\"anyResult\"), genResult = $(\"genResult\"), explainer = $(\"explainer\");\n  const presetButtons = document.querySelectorAll(\".presets button\");\n\n  const DATASETS = {\n    numbers: { label: \"numbers\", data: [1, 2, 3], type: \"number\" },\n    strings: { label: \"strings\", data: [\"ada\", \"grace\"], type: \"string\" },\n    objects: { label: \"objects\", data: [{ id: 1 }], type: \"object\" },\n  };\n\n  let current = \"numbers\";\n\n  presetButtons.forEach((btn) => {\n    btn.addEventListener(\"click\", () => {\n      current = btn.dataset.set;\n      presetButtons.forEach((b) => b.classList.toggle(\"active\", b === btn));\n      resetResults();\n    });\n  });\n\n  function resetResults() {\n    anyResult.className = \"result idle\";\n    anyResult.textContent = \"Pick a preset, then hit run.\";\n    genResult.className = \"result idle\";\n    genResult.textContent = \"Pick a preset, then hit run.\";\n    explainer.innerHTML = \"\u003Cstrong>What just happened:\u003C\u002Fstrong> pick a preset and press run to find out.\";\n  }\n\n  $(\"run\").addEventListener(\"click\", () => {\n    const set = DATASETS[current];\n    const first = set.data[0];\n\n    \u002F\u002F \"any\" version: TypeScript's real compiler would let this through with\n    \u002F\u002F zero checking (that's what `any` means) — so we actually run it, exactly\n    \u002F\u002F like the un-checked JavaScript underneath any TypeScript program would.\n    try {\n      const upper = first.toUpperCase();\n      anyResult.className = \"result ok\";\n      anyResult.innerHTML = \"\u003Cb>Compiled ✅ — ran ✅\u003C\u002Fb>Result: \\\"\" + upper + \"\\\"\";\n    } catch (e) {\n      anyResult.className = \"result fail\";\n      anyResult.innerHTML = \"\u003Cb>Compiled ✅ — crashed at runtime ❌\u003C\u002Fb>\" + e.message;\n    }\n\n    \u002F\u002F \"\u003CT>\" version: this is a simulation of what `tsc` itself would report —\n    \u002F\u002F the real compiler rejects this at COMPILE TIME, before any code runs,\n    \u002F\u002F because T is inferred as \"number\" or \"object\", neither of which has\n    \u002F\u002F .toUpperCase(). We simulate that gate here since there's no live\n    \u002F\u002F compiler in the browser, but the message mirrors tsc's real wording.\n    if (set.type === \"string\") {\n      genResult.className = \"result ok\";\n      genResult.innerHTML = \"\u003Cb>Compiled ✅ — ran ✅\u003C\u002Fb>T inferred as \u003Ccode>string\u003C\u002Fcode>. Result: \\\"\" + first.toUpperCase() + \"\\\"\";\n    } else {\n      genResult.className = \"result fail\";\n      genResult.innerHTML = \"\u003Cb>Rejected at compile time 🛑\u003C\u002Fb>Property 'toUpperCase' does not exist on type '\" + set.type + \"'.\";\n    }\n\n    explainer.innerHTML = set.type === \"string\"\n      ? \"\u003Cstrong>What just happened:\u003C\u002Fstrong> both versions worked, because the data really was a string this time. The difference only shows up when the data \u003Cem>doesn't\u003C\u002Fem> match — try the numbers or objects preset.\"\n      : \"\u003Cstrong>What just happened:\u003C\u002Fstrong> the \u003Ccode>any\u003C\u002Fcode> version let the call through and \" +\n        (set.type === \"number\" ? \"crashed when it actually ran\" : \"crashed when it actually ran\") +\n        \" — TypeScript had already stopped checking. The \u003Ccode>&lt;T&gt;\u003C\u002Fcode> version caught the same mistake before a single line ran, because T was inferred as \u003Ccode>\" + set.type + \"\u003C\u002Fcode>, which has no \u003Ccode>.toUpperCase()\u003C\u002Fcode>.\";\n  });\n\n  $(\"reset\").addEventListener(\"click\", resetResults);",{"height":11,"autorun":12},520,true,{"slug":4,"title":14,"excerpt":15,"coverUrl":16},"TypeScript Generics: The Complete Guide (with Cheat Sheet)","Learn TypeScript generics from the ground up — generic functions, constraints, defaults, and classes — with worked examples and a copy-paste cheat sheet.","\u002Fmedia\u002Fcovers\u002Fweekly-typescript-generics.png",[18,33],{"id":19,"slug":20,"name":21,"tagline":22,"description":23,"accentFrom":24,"accentTo":25,"icon":26,"defaultLocale":27,"locales":28,"features":30,"position":32},"019fe637-3d33-714b-b57f-23e163ffca0c","dev","Web Development","Build. Learn. Ship.","Practical courses, engineering-grade articles and open-source tools for people who ship.","violet-500","cyan-400","◇","en",[27,29],"fa",{"courses":12,"paths":12,"articles":12,"exams":31,"flashcards":31,"packages":12,"community":12,"certificates":12,"teams":12,"commerce":12},false,0,{"id":34,"slug":35,"name":36,"tagline":37,"description":38,"accentFrom":39,"accentTo":24,"icon":40,"defaultLocale":27,"locales":41,"features":43,"position":44},"019fe637-3dc2-754c-8657-0f175bfee7c6","lang","Languages","Learn a language the way you learn a codebase.","Structured paths, listening drills and spaced repetition that actually sticks.","amber-400","⌘",[27,29,42],"es",{"courses":12,"paths":12,"articles":31,"exams":31,"flashcards":31,"packages":31,"community":12,"certificates":31,"teams":31,"commerce":12},2]