diff --git a/404.html b/404.html index a0b2e30..b53be89 100644 --- a/404.html +++ b/404.html @@ -1 +1 @@ -
\ No newline at end of file +
\ No newline at end of file diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/about.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/about.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/about.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/about.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/build-a-db/part01.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/build-a-db/part01.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog/build-a-db/part01.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/build-a-db/part01.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/build-a-db/part02.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/build-a-db/part02.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog/build-a-db/part02.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/build-a-db/part02.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/build-a-db/part03.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/build-a-db/part03.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog/build-a-db/part03.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/build-a-db/part03.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/building-typescript-node-apps-with-nix.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/building-typescript-node-apps-with-nix.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog/building-typescript-node-apps-with-nix.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/building-typescript-node-apps-with-nix.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/efficient-nix-derivations-with-file-sets.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/efficient-nix-derivations-with-file-sets.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog/efficient-nix-derivations-with-file-sets.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/efficient-nix-derivations-with-file-sets.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/exposing-a-rust-library-to-node-with-napirs.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/exposing-a-rust-library-to-node-with-napirs.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog/exposing-a-rust-library-to-node-with-napirs.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/exposing-a-rust-library-to-node-with-napirs.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/intermediate-typescript-generics-and-mapped-types.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/intermediate-typescript-generics-and-mapped-types.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog/intermediate-typescript-generics-and-mapped-types.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/intermediate-typescript-generics-and-mapped-types.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/intermediate-typescript.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/intermediate-typescript.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog/intermediate-typescript.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/intermediate-typescript.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/organizing-system-configs-with-nixos.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/organizing-system-configs-with-nixos.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog/organizing-system-configs-with-nixos.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/organizing-system-configs-with-nixos.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/page/1.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/page/1.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog/page/1.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/page/1.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/page/2.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/page/2.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog/page/2.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/page/2.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/page/3.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/page/3.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog/page/3.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/page/3.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/rust-enviorment-and-docker-build-with-nix-flakes.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/rust-enviorment-and-docker-build-with-nix-flakes.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog/rust-enviorment-and-docker-build-with-nix-flakes.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/rust-enviorment-and-docker-build-with-nix-flakes.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/type-safe-groupby-in-typescript.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/type-safe-groupby-in-typescript.json similarity index 88% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog/type-safe-groupby-in-typescript.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/type-safe-groupby-in-typescript.json index e643e1d..bf14054 100644 --- a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/type-safe-groupby-in-typescript.json +++ b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/type-safe-groupby-in-typescript.json @@ -1 +1 @@ -{"pageProps":{"post":{"mdxSource":"var Component=(()=>{var i=Object.create;var c=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var F=Object.getOwnPropertyNames;var y=Object.getPrototypeOf,h=Object.prototype.hasOwnProperty;var a=r=>c(r,\"__esModule\",{value:!0});var m=(r,n)=>()=>(n||r((n={exports:{}}).exports,n),n.exports),u=(r,n)=>{a(r);for(var s in n)c(r,s,{get:n[s],enumerable:!0})},T=(r,n,s)=>{if(n&&typeof n==\"object\"||typeof n==\"function\")for(let l of F(n))!h.call(r,l)&&l!==\"default\"&&c(r,l,{get:()=>n[l],enumerable:!(s=p(n,l))||s.enumerable});return r},v=r=>T(a(c(r!=null?i(y(r)):{},\"default\",r&&r.__esModule&&\"default\"in r?{get:()=>r.default,enumerable:!0}:{value:r,enumerable:!0})),r);var d=m((R,t)=>{t.exports=_jsx_runtime});var f={};u(f,{default:()=>b,frontmatter:()=>K});var e=v(d()),K={title:\"Type Safe GroupBy In TypeScript\",date:\"2022-05-25\",tags:[\"typescript\",\"types\",\"code\",\"guide\"],draft:!1,summary:\"Create a better groupBy function that only allows valid keys to be grouped on\",images:[],layout:\"PostLayout\"};function g(r={}){let{wrapper:n}=r.components||{};return n?(0,e.jsx)(n,Object.assign({},r,{children:(0,e.jsx)(s,{})})):s();function s(){let l=Object.assign({h2:\"h2\",a:\"a\",span:\"span\",p:\"p\",pre:\"pre\",div:\"div\",code:\"code\",\"data-lsp\":\"data-lsp\",em:\"em\",\"data-err\":\"data-err\"},r.components),{TOCInline:o}=l;return o||C(\"TOCInline\",!0),(0,e.jsxs)(e.Fragment,{children:[(0,e.jsx)(o,{toc:r.toc,asDisclosure:!0}),`\n`,(0,e.jsxs)(l.h2,{id:\"lodashs-groupby\",children:[(0,e.jsx)(l.a,{\"aria-hidden\":\"true\",tabIndex:\"-1\",href:\"#lodashs-groupby\",children:(0,e.jsx)(l.span,{className:\"icon icon-link\"})}),\"Lodash's groupBy\"]}),`\n`,(0,e.jsxs)(l.p,{children:[\"I would bet if you have a sizeable Javascript/Typescript codebase you most likely are using \",(0,e.jsx)(l.a,{href:\"https://lodash.com/\",children:\"lodash\"}),` somewhere in there.\nWhile Javascript has gotten more \"batteries included\" over the last few years, lodash still has many nice functions for manipulating arrays/objects.\nOne such function is `,(0,e.jsx)(l.a,{href:\"https://lodash.com/docs/4.17.15#groupBy\",children:\"groupBy\"}),\". It groups a list by some predicate, in the simplest case it can just be a key in the objects of the array.\"]}),`\n\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"import\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:`(alias) namespace _\n(alias) const _: import(\"/home/runner/work/JRMurr.github.io/JRMurr.github.io/node_modules/@types/lodash/index.d.ts\").LoDashStatic\nimport _`,children:\"_\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"from\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"lodash\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"interface\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Foo\",children:\"Foo\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.num: number\",children:\"num\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"number\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'(property) Foo.someLiteral: \"a\" | \"b\" | \"c\"',children:\"someLiteral\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"a\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"|\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"b\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"|\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"c\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.object: Record\",children:\"object\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"string\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Foo\",children:\"Foo\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[] \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" { \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.num: number\",children:\"num\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"1\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\", \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'(property) Foo.someLiteral: \"a\" | \"b\" | \"c\"',children:\"someLiteral\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"a\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\", \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.object: Record\",children:\"object\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" { \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) key: string\",children:\"key\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"value\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" } },\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" { \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.num: number\",children:\"num\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"2\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\", \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'(property) Foo.someLiteral: \"a\" | \"b\" | \"c\"',children:\"someLiteral\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"a\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\", \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.object: Record\",children:\"object\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" { \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) key: string\",children:\"key\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"diffValue\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" } },\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" { \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.num: number\",children:\"num\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"1\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\", \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'(property) Foo.someLiteral: \"a\" | \"b\" | \"c\"',children:\"someLiteral\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"b\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\", \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.object: Record\",children:\"object\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {} },\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"];\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"var console: Console\",children:\"console\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Console.dir(item?: any, options?: any): void\",children:\"dir\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:`(alias) namespace _\n(alias) const _: import(\"/home/runner/work/JRMurr.github.io/JRMurr.github.io/node_modules/@types/lodash/index.d.ts\").LoDashStatic\nimport _`,children:\"_\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) LoDashStatic.groupBy(collection: _.List | null | undefined, iteratee?: _.ValueIteratee | undefined): _.Dictionary (+1 overload)\",children:\"groupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"num\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"));\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"/*\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"{\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" '1': [ { num: 1, someLiteral: 'a' }, { num: 1, someLiteral: 'b' } ],\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" '2': [ { num: 2, someLiteral: 'a' } ]\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"*/\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"var console: Console\",children:\"console\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Console.dir(item?: any, options?: any): void\",children:\"dir\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:`(alias) namespace _\n(alias) const _: import(\"/home/runner/work/JRMurr.github.io/JRMurr.github.io/node_modules/@types/lodash/index.d.ts\").LoDashStatic\nimport _`,children:\"_\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) LoDashStatic.groupBy(collection: _.List | null | undefined, iteratee?: _.ValueIteratee | undefined): _.Dictionary (+1 overload)\",children:\"groupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"someLiteral\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"));\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"/*\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"{\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" a:[\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" { num: 1, someLiteral: 'a', object: [Object] },\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" { num: 2, someLiteral: 'a', object: [Object] }\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" ],\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" b: [ { num: 1, someLiteral: 'b', object: {} } ]\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"*/\"})})]})})]}),`\n`,(0,e.jsx)(l.p,{children:\"This all seems to make sense, you can set what key you want to group on, and you get back an object whose keys are the values for found in the input array of objects.\"}),`\n`,(0,e.jsxs)(l.p,{children:[\"Now if you're in a TypeScript code base I hope you are using the \",(0,e.jsx)(l.a,{href:\"https://www.npmjs.com/package/@types/lodash\",children:\"definitely typed lodash types\"}),` to add some types to the lodash functions.\nIn this case the `,(0,e.jsx)(l.code,{children:\"_.groupBy\"}),\" type looks roughly like (simplified from the actual code)\"]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"declare\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"function\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function groupBy(collection: Array, key: string): Dictionary\",children:\"groupBy\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy(collection: T[], key: string): Dictionary\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">(\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) collection: T[]\",children:\"collection\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Array\",children:\"Array\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy(collection: T[], key: string): Dictionary\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">, \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: string\",children:\"key\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"string\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\")\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Dictionary\",children:\"Dictionary\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy(collection: T[], key: string): Dictionary\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]>;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"interface\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Dictionary\",children:\"Dictionary\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in Dictionary\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"> {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) index: string\",children:\"index\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"string\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"]\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in Dictionary\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"So a few things stick out here. First, the \",(0,e.jsx)(l.code,{children:\"key\"}),\" type is just string, so there's nothing stopping me from doing \",(0,e.jsx)(l.code,{children:'_.groupBy(vals, \"someKeyThatDoesNotExist\")'}),`.\nSecond, we have no restrictions at the type level of me grouping on a key whose value is not a valid object key (the value must be a subset of `,(0,e.jsx)(l.code,{children:\"string | number | symbol\"}),\"). For example in \",(0,e.jsx)(l.code,{children:\"Foo\"}),\" the \",(0,e.jsx)(l.code,{children:\"object\"}),\" key's value was a record. Here's what happens when you try to group on that key.\"]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"var console: Console\",children:\"console\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Console.dir(item?: any, options?: any): void\",children:\"dir\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:`(alias) namespace _\n(alias) const _: import(\"/home/runner/work/JRMurr.github.io/JRMurr.github.io/node_modules/@types/lodash/index.d.ts\").LoDashStatic\nimport _`,children:\"_\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) LoDashStatic.groupBy(collection: _.List | null | undefined, iteratee?: _.ValueIteratee | undefined): _.Dictionary (+1 overload)\",children:\"groupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"object\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"));\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"/*\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"{\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" '[object Object]': [\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" { num: 1, someLiteral: 'a', object: [Object] },\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" { num: 2, someLiteral: 'a', object: [Object] },\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" { num: 1, someLiteral: 'b', object: {} }\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" ]\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"*/\"})})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"In this case the objects where coerced to string values so all elements of \",(0,e.jsx)(l.code,{children:\"vals\"}),\" where grouped under the same weird \",(0,e.jsx)(l.code,{children:\"[object Object]\"}),\" key. While this does not throw an error there is almost 0 chance you want this to happen in your code.\"]}),`\n`,(0,e.jsxs)(l.p,{children:[\"Finally, the return type of this function is \",(0,e.jsx)(l.code,{children:\"Dictionary\"}),`, while its \"right\" it could be \"more right\" by encoding that the returning object's keys would be the values of the grouping key in the input object.`]}),`\n`,(0,e.jsxs)(l.h2,{id:\"making-our-own-groupby\",children:[(0,e.jsx)(l.a,{\"aria-hidden\":\"true\",tabIndex:\"-1\",href:\"#making-our-own-groupby\",children:(0,e.jsx)(l.span,{className:\"icon icon-link\"})}),\"Making our own groupBy\"]}),`\n`,(0,e.jsx)(l.p,{children:(0,e.jsx)(l.em,{children:\"insert Bender joke here\"})}),`\n`,(0,e.jsxs)(l.p,{children:[\"To start making our own type safe \",(0,e.jsx)(l.code,{children:\"groupBy\"}),\", we first need some code that actually does the grouping logic. Let's start with that and some basic types.\"]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// Note: PropertyKey is a builtIn type alias of\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// type PropertyKey = string | number | symbol\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:'// This lets us use \"Record\" to represent any object'})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:'// but is slightly nicer to use than the \"object\" type'})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"function\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function simpleGroupBy>(arr: T[], key: keyof T): any\",children:\"simpleGroupBy\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in simpleGroupBy>(arr: T[], key: keyof T): any\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type PropertyKey = string | number | symbol\",children:\"PropertyKey\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">>(\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in simpleGroupBy>(arr: T[], key: keyof T): any\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[], \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: keyof T\",children:\"key\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in simpleGroupBy>(arr: T[], key: keyof T): any\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\")\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.reduce(callbackfn: (previousValue: any, currentValue: T, currentIndex: number, array: T[]) => any, initialValue: any): any (+2 overloads)\",children:\"reduce\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"((\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: any\",children:\"accumulator\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\") \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=>\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: keyof T\",children:\"key\"}),\"];\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"if\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" (\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"!\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: any\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"}),\"]) {\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: any\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"}),\"] \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [];\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: any\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"}),\"].\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"any\",children:\"push\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"}),\");\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: any\",children:\"accumulator\"}),\";\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }, {} \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"as\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\");\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"var console: Console\",children:\"console\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Console.dir(item?: any, options?: any): void\",children:\"dir\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"(\"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function simpleGroupBy(arr: Foo[], key: keyof Foo): any\",children:\"simpleGroupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"num\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"));\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"/*\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"{\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" '1': [\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" { num: 1, someLiteral: 'a', object: [Object] },\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" { num: 1, someLiteral: 'b', object: {} }\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" ],\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" '2': [ { num: 2, someLiteral: 'a', object: [Object] } ]\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"*/\"})})]})})]}),`\n`,(0,e.jsx)(l.p,{children:\"Cool the logic here seems to work, but obviously the types could use some love.\"}),`\n`,(0,e.jsxs)(l.p,{children:[`Let's start by adding a few more generics, so we can type the output correctly.\nYour first change might be to make the return type `,(0,e.jsx)(l.code,{children:\"Record\"}),` since the keys will be coerced to strings by JavaScript and the values will be the same values in the array.\nThis will unfortunately make typescript sad.`]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"function\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function sadAttempt(arr: T[], key: keyof T): Record\",children:\"sadAttempt\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in sadAttempt(arr: T[], key: keyof T): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"object\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">(\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in sadAttempt(arr: T[], key: keyof T): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[], \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: keyof T\",children:\"key\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in sadAttempt(arr: T[], key: keyof T): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\")\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"string\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in sadAttempt(arr: T[], key: keyof T): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]> {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.reduce>(callbackfn: (previousValue: Record, currentValue: T, currentIndex: number, array: T[]) => Record, initialValue: Record<...>): Record<...> (+2 overloads)\",children:\"reduce\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"((\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends object\",children:\"val\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\") \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=>\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends object\",children:\"val\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: keyof T\",children:\"key\"}),\"];\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"if\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" (\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"!\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsxs)(l[\"data-err\"],{children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"})]}),\"]) {\"]})]}),(0,e.jsxs)(l.span,{className:\"error\",children:[(0,e.jsx)(l.span,{children:\"Type 'T[keyof T]' cannot be used to index type 'Record'.\"}),(0,e.jsx)(l.span,{className:\"code\",children:\"2536\"})]}),(0,e.jsx)(l.span,{className:\"error-behind\",children:\"Type 'T[keyof T]' cannot be used to index type 'Record'.\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsxs)(l[\"data-err\"],{children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"})]}),\"] \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [];\"})]}),(0,e.jsxs)(l.span,{className:\"error\",children:[(0,e.jsx)(l.span,{children:\"Type 'T[keyof T]' cannot be used to index type 'Record'.\"}),(0,e.jsx)(l.span,{className:\"code\",children:\"2536\"})]}),(0,e.jsx)(l.span,{className:\"error-behind\",children:\"Type 'T[keyof T]' cannot be used to index type 'Record'.\"}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsxs)(l[\"data-err\"],{children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"})]}),\"].\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"any\",children:\"push\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends object\",children:\"val\"}),\");\"]})]}),(0,e.jsxs)(l.span,{className:\"error\",children:[(0,e.jsx)(l.span,{children:\"Type 'T[keyof T]' cannot be used to index type 'Record'.\"}),(0,e.jsx)(l.span,{className:\"code\",children:\"2536\"})]}),(0,e.jsx)(l.span,{className:\"error-behind\",children:\"Type 'T[keyof T]' cannot be used to index type 'Record'.\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\";\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }, {} \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"as\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"string\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in sadAttempt(arr: T[], key: keyof T): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]>);\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"The lines with \",(0,e.jsx)(l.code,{children:\"accumulator[groupedKey]\"}),\" will error with \",(0,e.jsx)(l.code,{children:\"Type 'T[keyof T]' cannot be used to index type 'Record'\"}),\". Here the \",(0,e.jsx)(l.code,{children:\"keyof T\"}),\" could be any key in \",(0,e.jsx)(l.code,{children:\"T\"}),\" so since not every key's value in \",(0,e.jsx)(l.code,{children:\"T\"}),\" is a string typescript will not let you treat \",(0,e.jsx)(l.code,{children:\"groupedKey\"}),\" as a string.\"]}),`\n`,(0,e.jsx)(l.p,{children:\"We can almost fix this by adding some more information on the input key by binding it to a new generic parameter, though there will still be some issues.\"}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"function\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"betterSadAttempt\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type PropertyKey = string | number | symbol\",children:\"PropertyKey\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">, \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"Key\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">(\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[],\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: Key extends keyof T\",children:\"key\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"Key\"})})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\")\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"Key\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"], \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]> {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.reduce>(callbackfn: (previousValue: Record, currentValue: T, currentIndex: number, array: T[]) => Record, initialValue: Record<...>): Record<...> (+2 overloads)\",children:\"reduce\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"((\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\") \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=>\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: Key extends keyof T\",children:\"key\"}),\"];\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"if\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" (\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"!\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\"]) {\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\"] \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [];\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\"].\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.push(...items: T[]): number\",children:\"push\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"}),\");\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\";\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }, {} \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"as\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"Key\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"], \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]>);\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"Here we added a new generic \",(0,e.jsx)(l.code,{children:\"Key extends keyof T\"}),\" so when we supply a specific key to the function, the Key generic will be narrowed to that value. For example if we did \",(0,e.jsx)(l.code,{children:\"betterSadAttempt(vals, 'someLiteral')\"}),\", \",(0,e.jsx)(l.code,{children:\"Key\"}),\" would exactly be \",(0,e.jsx)(l.code,{children:\"'someLiteral'\"}),\" instead of \",(0,e.jsx)(l.code,{children:\"keyof Foo = 'someLiteral' | 'num' | 'object'\"})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"However, typescript is still sad on the \",(0,e.jsx)(l.code,{children:\"Record\"}),\" lines with \",(0,e.jsx)(l.code,{children:\"Type 'T[Key]' does not satisfy the constraint 'string | number | symbol'\"}),`.\nThis error is similar to the error before, basically `,(0,e.jsx)(l.code,{children:\"T[Key]\"}),\" can not be a key for the \",(0,e.jsx)(l.code,{children:\"Record\"}),\" since it could be some weird value.\"]}),`\n`,(0,e.jsxs)(l.p,{children:[\"To accomplish this we need to make a helper type that filters down the allowed keys to only keys whose values are \",(0,e.jsx)(l.code,{children:\"string | number | symbol\"}),`.\nWe can use a `,(0,e.jsx)(l.a,{href:\"https://www.typescriptlang.org/docs/handbook/2/mapped-types.html\",children:\"mapped type\"}),\" to do just that\"]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type MapValuesToKeysIfAllowed = { [K in keyof T]: T[K] extends PropertyKey ? K : never; }\",children:\"MapValuesToKeysIfAllowed\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type MapValuesToKeysIfAllowed\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"> \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) K\",children:\"K\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"in\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type MapValuesToKeysIfAllowed\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"]\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type MapValuesToKeysIfAllowed\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) K\",children:\"K\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"] \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type PropertyKey = string | number | symbol\",children:\"PropertyKey\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"?\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) K\",children:\"K\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"never\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"};\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Filter = MapValuesToKeysIfAllowed[keyof T]\",children:\"Filter\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"> \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type MapValuesToKeysIfAllowed = { [K in keyof T]: T[K] extends PropertyKey ? K : never; }\",children:\"MapValuesToKeysIfAllowed\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">[\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"];\"})]})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"This type helper does a few things. First it maps over all the values in \",(0,e.jsx)(l.code,{children:\"T\"}),\" (\",(0,e.jsx)(l.code,{children:\"[K in keyof T]\"}),\") and makes the value the key if it is a subset of \",(0,e.jsx)(l.code,{children:\"string | number | symbol\"}),\" (\",(0,e.jsx)(l.code,{children:\"T[K] extends PropertyKey ? K\"}),\"), if it's not a subset its value will be the \",(0,e.jsx)(l.code,{children:\"never\"}),\" type. Finally, we use an \",(0,e.jsx)(l.a,{href:\"https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html\",children:\"index access type\"}),\" to get all values of the transformed object as a union. This step will drop all the \",(0,e.jsx)(l.code,{children:\"never\"}),\" values automatically for us since adding \",(0,e.jsx)(l.code,{children:\"never\"}),\" to a union is like saying \",(0,e.jsx)(l.code,{children:\"or false\"}),\" its basically is a no op.\"]}),`\n`,(0,e.jsx)(l.p,{children:\"That was a mouthful so let's see an example\"}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// from above\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"interface\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Foo\",children:\"Foo\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.num: number\",children:\"num\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"number\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'(property) Foo.someLiteral: \"a\" | \"b\" | \"c\"',children:\"someLiteral\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"a\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"|\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"b\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"|\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"c\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.object: Record\",children:\"object\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"string\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:`type MappedFoo = {\n num: \"num\";\n someLiteral: \"someLiteral\";\n object: never;\n}`,children:\"MappedFoo\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type MapValuesToKeysIfAllowed = { [K in keyof T]: T[K] extends PropertyKey ? K : never; }\",children:\"MapValuesToKeysIfAllowed\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Foo\",children:\"Foo\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"/*\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"{\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:' num: \"num\";'})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:' someLiteral: \"someLiteral\";'})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" object: never;\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"*/\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// we replace the values of this object with just the key as a string literal or never\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:'type FooKeys = \"num\" | \"someLiteral\"',children:\"FooKeys\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Filter = MapValuesToKeysIfAllowed[keyof T]\",children:\"Filter\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Foo\",children:\"Foo\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:'// => \"num\" | \"someLiteral\"'})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// notice the never does not show up in the union\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"interface\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface AllObjects\",children:\"AllObjects\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) AllObjects.object: Record\",children:\"object\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"string\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) AllObjects.diffObject: Record\",children:\"diffObject\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"number\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:`type MappedAllObjects = {\n object: never;\n diffObject: never;\n}`,children:\"MappedAllObjects\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type MapValuesToKeysIfAllowed = { [K in keyof T]: T[K] extends PropertyKey ? K : never; }\",children:\"MapValuesToKeysIfAllowed\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface AllObjects\",children:\"AllObjects\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"/*\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"{ \"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" object: never;\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" diffObject: never;\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"*/\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type AllObjectsKeys = never\",children:\"AllObjectsKeys\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Filter = MapValuesToKeysIfAllowed[keyof T]\",children:\"Filter\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface AllObjects\",children:\"AllObjects\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// => never\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:'// the output is only never. Think of this like saying \"false or false\", the output will just be false'})})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"With this filter type helper function we can now properly limit the \",(0,e.jsx)(l.code,{children:\"Key\"}),\" generic by replacing \",(0,e.jsx)(l.code,{children:\"Key extends keyof T\"}),\" with \",(0,e.jsx)(l.code,{children:\"Key extends Filter\"}),\".\"]}),`\n`,(0,e.jsxs)(l.h2,{id:\"putting-it-all-together\",children:[(0,e.jsx)(l.a,{\"aria-hidden\":\"true\",tabIndex:\"-1\",href:\"#putting-it-all-together\",children:(0,e.jsx)(l.span,{className:\"icon icon-link\"})}),\"Putting it all together\"]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type MapValuesToKeysIfAllowed = { [K in keyof T]: T[K] extends PropertyKey ? K : never; }\",children:\"MapValuesToKeysIfAllowed\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type MapValuesToKeysIfAllowed\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"> \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) K\",children:\"K\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"in\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type MapValuesToKeysIfAllowed\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"]\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type MapValuesToKeysIfAllowed\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) K\",children:\"K\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"] \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type PropertyKey = string | number | symbol\",children:\"PropertyKey\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"?\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) K\",children:\"K\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"never\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"};\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Filter = MapValuesToKeysIfAllowed[keyof T]\",children:\"Filter\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"> \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type MapValuesToKeysIfAllowed = { [K in keyof T]: T[K] extends PropertyKey ? K : never; }\",children:\"MapValuesToKeysIfAllowed\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">[\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"];\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"function\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"groupBy\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type PropertyKey = string | number | symbol\",children:\"PropertyKey\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">, \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"Key\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Filter = MapValuesToKeysIfAllowed[keyof T]\",children:\"Filter\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">>(\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[],\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: Key extends Filter\",children:\"key\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"Key\"})})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\")\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"Key\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"], \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]> {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.reduce>(callbackfn: (previousValue: Record, currentValue: T, currentIndex: number, array: T[]) => Record, initialValue: Record<...>): Record<...> (+2 overloads)\",children:\"reduce\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"((\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\") \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=>\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: Key extends Filter\",children:\"key\"}),\"];\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"if\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" (\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"!\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\"]) {\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\"] \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [];\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\"].\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.push(...items: T[]): number\",children:\"push\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"}),\");\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\";\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }, {} \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"as\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"Key\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"], \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]>);\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const nums: Record\",children:\"nums\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:'function groupBy(arr: Foo[], key: \"num\"): Record',children:\"groupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"num\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\");\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// nums = Record\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'const literals: Record<\"a\" | \"b\" | \"c\", Foo[]>',children:\"literals\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:'function groupBy(arr: Foo[], key: \"someLiteral\"): Record<\"a\" | \"b\" | \"c\", Foo[]>',children:\"groupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"someLiteral\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\");\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:'// literals = Record<\"a\" | \"b\" | \"c\", Foo[]>'})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'const sad: Record',children:\"sad\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:'function groupBy>(arr: Foo[], key: Filter): Record',children:\"groupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"object\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\");\"})]}),(0,e.jsxs)(l.span,{className:\"error\",children:[(0,e.jsx)(l.span,{children:`Argument of type '\"object\"' is not assignable to parameter of type 'Filter'.`}),(0,e.jsx)(l.span,{className:\"code\",children:\"2345\"})]}),(0,e.jsx)(l.span,{className:\"error-behind\",children:`Argument of type '\"object\"' is not assignable to parameter of type 'Filter'.`})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[`Now this works great, we can only pass in keys that have valid values, and we even get autocomplete on it! However, one thing that bothers me is the error message in the last case.\nWhile it's correct, saying `,(0,e.jsx)(l.code,{children:\"not assignable to parameter of type 'Filter'\"}),\" is not very useful to a user. This pops up sometimes with typescript where it won't show the underlying type and instead just show the higher level type helper instead.\"]}),`\n`,(0,e.jsxs)(l.p,{children:[\"To make the error message show the valid keys we can use a modified version of \",(0,e.jsx)(l.a,{href:\"https://stackoverflow.com/a/57683652\",children:'this \"hack\"'}),\". Here instead of creating the \",(0,e.jsx)(l.code,{children:\"Expand\"}),\" type in the post, we can make our own \",(0,e.jsx)(l.code,{children:\"ValuesOf\"}),\" to replace the \",(0,e.jsx)(l.code,{children:\"[keyof T]\"}),\" at the end of \",(0,e.jsx)(l.code,{children:\"Filter\"})]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type ValuesOf = A extends infer O ? A[keyof A] : never\",children:\"ValuesOf\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) A in type ValuesOf\",children:\"A\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"> \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) A in type ValuesOf\",children:\"A\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"infer\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) O\",children:\"O\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"?\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) A in type ValuesOf\",children:\"A\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) A in type ValuesOf\",children:\"A\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"] \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"never\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Filter = MapValuesToKeysIfAllowed extends infer O ? (O & MapValuesToKeysIfAllowed)[keyof T | keyof O] : never\",children:\"Filter\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"> \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type ValuesOf = A extends infer O ? A[keyof A] : never\",children:\"ValuesOf\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type MapValuesToKeysIfAllowed = { [K in keyof T]: T[K] extends PropertyKey ? K : never; }\",children:\"MapValuesToKeysIfAllowed\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">>;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// was Filter = MapValuesToKeysIfAllowed[keyof T]\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'const sad: Record',children:\"sad\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:'function groupBy(arr: Foo[], key: \"num\" | \"someLiteral\"): Record',children:\"groupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"object\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\");\"})]}),(0,e.jsxs)(l.span,{className:\"error\",children:[(0,e.jsx)(l.span,{children:`Argument of type '\"object\"' is not assignable to parameter of type '\"num\" | \"someLiteral\"'.`}),(0,e.jsx)(l.span,{className:\"code\",children:\"2345\"})]}),(0,e.jsx)(l.span,{className:\"error-behind\",children:`Argument of type '\"object\"' is not assignable to parameter of type '\"num\" | \"someLiteral\"'.`})]})})]}),`\n`,(0,e.jsx)(l.p,{children:\"Now we have type safety and good error messages!\"}),`\n`,(0,e.jsxs)(l.h2,{id:\"possible-improvements\",children:[(0,e.jsx)(l.a,{\"aria-hidden\":\"true\",tabIndex:\"-1\",href:\"#possible-improvements\",children:(0,e.jsx)(l.span,{className:\"icon icon-link\"})}),\"Possible improvements\"]}),`\n`,(0,e.jsxs)(l.p,{children:[\"One thing this \",(0,e.jsx)(l.code,{children:\"groupBy\"}),\" function lacks that the lodash \",(0,e.jsx)(l.code,{children:\"groupBy\"}),` gives is we do not allow you to pass a function instead of a key to group on.\nThe example in the lodash docs is`]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:`(alias) namespace _\n(alias) const _: import(\"/home/runner/work/JRMurr.github.io/JRMurr.github.io/node_modules/@types/lodash/index.d.ts\").LoDashStatic\nimport _`,children:\"_\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) LoDashStatic.groupBy(collection: _.List | null | undefined, iteratee?: _.ValueIteratee | undefined): _.Dictionary (+1 overload)\",children:\"groupBy\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"([\"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"6.1\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"4.2\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"6.3\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"], \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"var Math: Math\",children:\"Math\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\".\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Math.floor(x: number): number\",children:\"floor\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\");\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// { '4': [4.2], '6': [6.1, 6.3] }\"})})]})})]}),`\n`,(0,e.jsx)(l.p,{children:\"While this is not perfect this mostly works\"}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"function\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function groupByFunc RetType>(arr: T[], mapper: Func): Record\",children:\"groupByFunc\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) RetType in groupByFunc RetType>(arr: T[], mapper: Func): Record\",children:\"RetType\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type PropertyKey = string | number | symbol\",children:\"PropertyKey\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\",\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupByFunc RetType>(arr: T[], mapper: Func): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// no longer need any requirements on T since the grouper can do w/e it wants\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Func in groupByFunc RetType>(arr: T[], mapper: Func): Record\",children:\"Func\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" (\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arg: T\",children:\"arg\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupByFunc RetType>(arr: T[], mapper: Func): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\") \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=>\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) RetType in groupByFunc RetType>(arr: T[], mapper: Func): Record\",children:\"RetType\"})})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">(\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupByFunc RetType>(arr: T[], mapper: Func): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[], \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) mapper: Func extends (arg: T) => RetType\",children:\"mapper\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Func in groupByFunc RetType>(arr: T[], mapper: Func): Record\",children:\"Func\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\")\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) RetType in groupByFunc RetType>(arr: T[], mapper: Func): Record\",children:\"RetType\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupByFunc RetType>(arr: T[], mapper: Func): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]> {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.reduce>(callbackfn: (previousValue: Record, currentValue: T, currentIndex: number, array: T[]) => Record, initialValue: Record<...>): Record<...> (+2 overloads)\",children:\"reduce\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"((\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T\",children:\"val\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\") \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=>\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: RetType extends PropertyKey\",children:\"groupedKey\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:`(parameter) mapper: Func\n(arg: T) => RetType`,children:\"mapper\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T\",children:\"val\"}),\");\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"if\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" (\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"!\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: RetType extends PropertyKey\",children:\"groupedKey\"}),\"]) {\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: RetType extends PropertyKey\",children:\"groupedKey\"}),\"] \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [];\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: RetType extends PropertyKey\",children:\"groupedKey\"}),\"].\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.push(...items: T[]): number\",children:\"push\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T\",children:\"val\"}),\");\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\";\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }, {} \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"as\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) RetType in groupByFunc RetType>(arr: T[], mapper: Func): Record\",children:\"RetType\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupByFunc RetType>(arr: T[], mapper: Func): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]>);\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const test: Record\",children:\"test\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function groupByFunc number>(arr: number[], mapper: (x: number) => number): Record\",children:\"groupByFunc\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"([\"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"6.1\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"4.2\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"6.3\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"], \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"var Math: Math\",children:\"Math\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\".\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Math.floor(x: number): number\",children:\"floor\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\");\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// test = Record\"})})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"This works by only letting you pass in functions that return \",(0,e.jsx)(l.code,{children:\"PropertyKey\"}),\", but typescript does not seem to narrow the types. In this case \",(0,e.jsx)(l.code,{children:\"test\"}),\" should be \",(0,e.jsx)(l.code,{children:\"Record\"}),\" since TS \",(0,e.jsx)(l.em,{children:\"should\"}),\" infer the return type of the grouping function. If you know how to improve this function to make the return type narrow properly feel free to leave an issue/pr on my \",(0,e.jsx)(l.a,{href:\"https://github.com/JRMurr/JRMurr.github.io\",children:\"blog's GitHub\"}),\"!\"]})]})}}var b=g;function C(r,n){throw new Error(\"Expected \"+(n?\"component\":\"object\")+\" `\"+r+\"` to be defined: you likely forgot to import, pass, or provide it.\")}return f;})();\n;return Component;","toc":[{"value":"Lodash's groupBy","url":"#lodashs-groupby","depth":2},{"value":"Making our own groupBy","url":"#making-our-own-groupby","depth":2},{"value":"Putting it all together","url":"#putting-it-all-together","depth":2},{"value":"Possible improvements","url":"#possible-improvements","depth":2}],"frontMatter":{"readingTime":{"text":"16 min read","minutes":15.883333333333333,"time":953000,"words":3812},"slug":"type-safe-groupby-in-typescript","fileName":"type-safe-groupby-in-typescript.md","title":"Type Safe GroupBy In TypeScript","date":"2022-05-25T00:00:00.000Z","tags":["typescript","types","code","guide"],"draft":false,"summary":"Create a better groupBy function that only allows valid keys to be grouped on","images":[],"layout":"PostLayout"}},"authorDetails":[{"readingTime":{"text":"1 min read","minutes":0.17916666666666667,"time":10750,"words":43},"slug":["default"],"fileName":"default.md","name":"John Murray","avatar":"/static/images/me.jpg","occupation":"Software Engineer","github":"https://github.com/JRMurr","twitter":"https://twitter.com/JRMurrCodes","mastodon":"https://hachyderm.io/@jrmurr","email":"johnreillymurray@gmail.com","date":null}],"series":null},"__N_SSG":true} \ No newline at end of file +{"pageProps":{"post":{"mdxSource":"var Component=(()=>{var i=Object.create;var c=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var F=Object.getOwnPropertyNames;var y=Object.getPrototypeOf,h=Object.prototype.hasOwnProperty;var a=r=>c(r,\"__esModule\",{value:!0});var m=(r,s)=>()=>(s||r((s={exports:{}}).exports,s),s.exports),u=(r,s)=>{a(r);for(var n in s)c(r,n,{get:s[n],enumerable:!0})},T=(r,s,n)=>{if(s&&typeof s==\"object\"||typeof s==\"function\")for(let l of F(s))!h.call(r,l)&&l!==\"default\"&&c(r,l,{get:()=>s[l],enumerable:!(n=p(s,l))||n.enumerable});return r},v=r=>T(a(c(r!=null?i(y(r)):{},\"default\",r&&r.__esModule&&\"default\"in r?{get:()=>r.default,enumerable:!0}:{value:r,enumerable:!0})),r);var d=m((N,t)=>{t.exports=_jsx_runtime});var f={};u(f,{default:()=>b,frontmatter:()=>K});var e=v(d()),K={title:\"Type Safe GroupBy In TypeScript\",date:\"2022-05-25\",tags:[\"typescript\",\"types\",\"code\",\"guide\"],draft:!1,summary:\"Create a better groupBy function that only allows valid keys to be grouped on\",images:[],layout:\"PostLayout\"};function g(r={}){let{wrapper:s}=r.components||{};return s?(0,e.jsx)(s,Object.assign({},r,{children:(0,e.jsx)(n,{})})):n();function n(){let l=Object.assign({h2:\"h2\",a:\"a\",span:\"span\",p:\"p\",pre:\"pre\",div:\"div\",code:\"code\",\"data-lsp\":\"data-lsp\",em:\"em\",\"data-err\":\"data-err\"},r.components),{TOCInline:o}=l;return o||C(\"TOCInline\",!0),(0,e.jsxs)(e.Fragment,{children:[(0,e.jsx)(o,{toc:r.toc,asDisclosure:!0}),`\n`,(0,e.jsxs)(l.h2,{id:\"lodashs-groupby\",children:[(0,e.jsx)(l.a,{\"aria-hidden\":\"true\",tabIndex:\"-1\",href:\"#lodashs-groupby\",children:(0,e.jsx)(l.span,{className:\"icon icon-link\"})}),\"Lodash's groupBy\"]}),`\n`,(0,e.jsxs)(l.p,{children:[\"I would bet if you have a sizeable Javascript/Typescript codebase you most likely are using \",(0,e.jsx)(l.a,{href:\"https://lodash.com/\",children:\"lodash\"}),` somewhere in there.\nWhile Javascript has gotten more \"batteries included\" over the last few years, lodash still has many nice functions for manipulating arrays/objects.\nOne such function is `,(0,e.jsx)(l.a,{href:\"https://lodash.com/docs/4.17.15#groupBy\",children:\"groupBy\"}),\". It groups a list by some predicate, in the simplest case it can just be a key in the objects of the array.\"]}),`\n\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"import\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:`(alias) namespace _\n(alias) const _: import(\"/home/runner/work/JRMurr.github.io/JRMurr.github.io/node_modules/@types/lodash/index.d.ts\").LoDashStatic\nimport _`,children:\"_\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"from\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"lodash\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"interface\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Foo\",children:\"Foo\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.num: number\",children:\"num\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"number\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'(property) Foo.someLiteral: \"a\" | \"b\" | \"c\"',children:\"someLiteral\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"a\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"|\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"b\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"|\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"c\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.object: Record\",children:\"object\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"string\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Foo\",children:\"Foo\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[] \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" { \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.num: number\",children:\"num\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"1\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\", \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'(property) Foo.someLiteral: \"a\" | \"b\" | \"c\"',children:\"someLiteral\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"a\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\", \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.object: Record\",children:\"object\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" { \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) key: string\",children:\"key\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"value\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" } },\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" { \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.num: number\",children:\"num\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"2\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\", \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'(property) Foo.someLiteral: \"a\" | \"b\" | \"c\"',children:\"someLiteral\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"a\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\", \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.object: Record\",children:\"object\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" { \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) key: string\",children:\"key\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"diffValue\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" } },\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" { \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.num: number\",children:\"num\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"1\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\", \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'(property) Foo.someLiteral: \"a\" | \"b\" | \"c\"',children:\"someLiteral\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"b\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\", \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.object: Record\",children:\"object\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {} },\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"];\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"var console: Console\",children:\"console\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Console.dir(item?: any, options?: any): void\",children:\"dir\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:`(alias) namespace _\n(alias) const _: import(\"/home/runner/work/JRMurr.github.io/JRMurr.github.io/node_modules/@types/lodash/index.d.ts\").LoDashStatic\nimport _`,children:\"_\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) LoDashStatic.groupBy(collection: _.List | null | undefined, iteratee?: _.ValueIteratee | undefined): _.Dictionary (+1 overload)\",children:\"groupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"num\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"));\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"/*\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"{\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" '1': [ { num: 1, someLiteral: 'a' }, { num: 1, someLiteral: 'b' } ],\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" '2': [ { num: 2, someLiteral: 'a' } ]\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"*/\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"var console: Console\",children:\"console\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Console.dir(item?: any, options?: any): void\",children:\"dir\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:`(alias) namespace _\n(alias) const _: import(\"/home/runner/work/JRMurr.github.io/JRMurr.github.io/node_modules/@types/lodash/index.d.ts\").LoDashStatic\nimport _`,children:\"_\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) LoDashStatic.groupBy(collection: _.List | null | undefined, iteratee?: _.ValueIteratee | undefined): _.Dictionary (+1 overload)\",children:\"groupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"someLiteral\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"));\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"/*\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"{\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" a:[\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" { num: 1, someLiteral: 'a', object: [Object] },\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" { num: 2, someLiteral: 'a', object: [Object] }\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" ],\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" b: [ { num: 1, someLiteral: 'b', object: {} } ]\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"*/\"})})]})})]}),`\n`,(0,e.jsx)(l.p,{children:\"This all seems to make sense, you can set what key you want to group on, and you get back an object whose keys are the values for found in the input array of objects.\"}),`\n`,(0,e.jsxs)(l.p,{children:[\"Now if you're in a TypeScript code base I hope you are using the \",(0,e.jsx)(l.a,{href:\"https://www.npmjs.com/package/@types/lodash\",children:\"definitely typed lodash types\"}),` to add some types to the lodash functions.\nIn this case the `,(0,e.jsx)(l.code,{children:\"_.groupBy\"}),\" type looks roughly like (simplified from the actual code)\"]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"declare\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"function\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function groupBy(collection: Array, key: string): Dictionary\",children:\"groupBy\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy(collection: T[], key: string): Dictionary\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">(\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) collection: T[]\",children:\"collection\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Array\",children:\"Array\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy(collection: T[], key: string): Dictionary\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">, \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: string\",children:\"key\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"string\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\")\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Dictionary\",children:\"Dictionary\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy(collection: T[], key: string): Dictionary\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]>;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"interface\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Dictionary\",children:\"Dictionary\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in Dictionary\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"> {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) index: string\",children:\"index\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"string\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"]\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in Dictionary\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"So a few things stick out here. First, the \",(0,e.jsx)(l.code,{children:\"key\"}),\" type is just string, so there's nothing stopping me from doing \",(0,e.jsx)(l.code,{children:'_.groupBy(vals, \"someKeyThatDoesNotExist\")'}),`.\nSecond, we have no restrictions at the type level of me grouping on a key whose value is not a valid object key (the value must be a subset of `,(0,e.jsx)(l.code,{children:\"string | number | symbol\"}),\"). For example in \",(0,e.jsx)(l.code,{children:\"Foo\"}),\" the \",(0,e.jsx)(l.code,{children:\"object\"}),\" key's value was a record. Here's what happens when you try to group on that key.\"]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"var console: Console\",children:\"console\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Console.dir(item?: any, options?: any): void\",children:\"dir\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:`(alias) namespace _\n(alias) const _: import(\"/home/runner/work/JRMurr.github.io/JRMurr.github.io/node_modules/@types/lodash/index.d.ts\").LoDashStatic\nimport _`,children:\"_\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) LoDashStatic.groupBy(collection: _.List | null | undefined, iteratee?: _.ValueIteratee | undefined): _.Dictionary (+1 overload)\",children:\"groupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"object\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"));\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"/*\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"{\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" '[object Object]': [\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" { num: 1, someLiteral: 'a', object: [Object] },\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" { num: 2, someLiteral: 'a', object: [Object] },\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" { num: 1, someLiteral: 'b', object: {} }\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" ]\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"*/\"})})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"In this case the objects where coerced to string values so all elements of \",(0,e.jsx)(l.code,{children:\"vals\"}),\" where grouped under the same weird \",(0,e.jsx)(l.code,{children:\"[object Object]\"}),\" key. While this does not throw an error there is almost 0 chance you want this to happen in your code.\"]}),`\n`,(0,e.jsxs)(l.p,{children:[\"Finally, the return type of this function is \",(0,e.jsx)(l.code,{children:\"Dictionary\"}),`, while its \"right\" it could be \"more right\" by encoding that the returning object's keys would be the values of the grouping key in the input object.`]}),`\n`,(0,e.jsxs)(l.h2,{id:\"making-our-own-groupby\",children:[(0,e.jsx)(l.a,{\"aria-hidden\":\"true\",tabIndex:\"-1\",href:\"#making-our-own-groupby\",children:(0,e.jsx)(l.span,{className:\"icon icon-link\"})}),\"Making our own groupBy\"]}),`\n`,(0,e.jsx)(l.p,{children:(0,e.jsx)(l.em,{children:\"insert Bender joke here\"})}),`\n`,(0,e.jsxs)(l.p,{children:[\"To start making our own type safe \",(0,e.jsx)(l.code,{children:\"groupBy\"}),\", we first need some code that actually does the grouping logic. Let's start with that and some basic types.\"]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// Note: PropertyKey is a builtIn type alias of\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// type PropertyKey = string | number | symbol\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:'// This lets us use \"Record\" to represent any object'})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:'// but is slightly nicer to use than the \"object\" type'})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"function\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function simpleGroupBy>(arr: T[], key: keyof T): any\",children:\"simpleGroupBy\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in simpleGroupBy>(arr: T[], key: keyof T): any\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type PropertyKey = string | number | symbol\",children:\"PropertyKey\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">>(\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in simpleGroupBy>(arr: T[], key: keyof T): any\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[], \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: keyof T\",children:\"key\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in simpleGroupBy>(arr: T[], key: keyof T): any\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\")\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.reduce(callbackfn: (previousValue: any, currentValue: T, currentIndex: number, array: T[]) => any, initialValue: any): any (+2 overloads)\",children:\"reduce\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"((\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: any\",children:\"accumulator\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\") \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=>\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: keyof T\",children:\"key\"}),\"];\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"if\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" (\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"!\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: any\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"}),\"]) {\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: any\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"}),\"] \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [];\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: any\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"}),\"].\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"any\",children:\"push\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"}),\");\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: any\",children:\"accumulator\"}),\";\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }, {} \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"as\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\");\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"var console: Console\",children:\"console\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Console.dir(item?: any, options?: any): void\",children:\"dir\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"(\"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function simpleGroupBy(arr: Foo[], key: keyof Foo): any\",children:\"simpleGroupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"num\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"));\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"/*\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"{\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" '1': [\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" { num: 1, someLiteral: 'a', object: [Object] },\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" { num: 1, someLiteral: 'b', object: {} }\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" ],\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" '2': [ { num: 2, someLiteral: 'a', object: [Object] } ]\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"*/\"})})]})})]}),`\n`,(0,e.jsx)(l.p,{children:\"Cool the logic here seems to work, but obviously the types could use some love.\"}),`\n`,(0,e.jsxs)(l.p,{children:[`Let's start by adding a few more generics, so we can type the output correctly.\nYour first change might be to make the return type `,(0,e.jsx)(l.code,{children:\"Record\"}),` since the keys will be coerced to strings by JavaScript and the values will be the same values in the array.\nThis will unfortunately make typescript sad.`]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"function\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function sadAttempt(arr: T[], key: keyof T): Record\",children:\"sadAttempt\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in sadAttempt(arr: T[], key: keyof T): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"object\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">(\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in sadAttempt(arr: T[], key: keyof T): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[], \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: keyof T\",children:\"key\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in sadAttempt(arr: T[], key: keyof T): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\")\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"string\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in sadAttempt(arr: T[], key: keyof T): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]> {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.reduce>(callbackfn: (previousValue: Record, currentValue: T, currentIndex: number, array: T[]) => Record, initialValue: Record<...>): Record<...> (+2 overloads)\",children:\"reduce\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"((\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends object\",children:\"val\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\") \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=>\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends object\",children:\"val\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: keyof T\",children:\"key\"}),\"];\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"if\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" (\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"!\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsxs)(l[\"data-err\"],{children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"})]}),\"]) {\"]})]}),(0,e.jsxs)(l.span,{className:\"error\",children:[(0,e.jsx)(l.span,{children:\"Type 'T[keyof T]' cannot be used to index type 'Record'.\"}),(0,e.jsx)(l.span,{className:\"code\",children:\"2536\"})]}),(0,e.jsx)(l.span,{className:\"error-behind\",children:\"Type 'T[keyof T]' cannot be used to index type 'Record'.\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsxs)(l[\"data-err\"],{children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"})]}),\"] \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [];\"})]}),(0,e.jsxs)(l.span,{className:\"error\",children:[(0,e.jsx)(l.span,{children:\"Type 'T[keyof T]' cannot be used to index type 'Record'.\"}),(0,e.jsx)(l.span,{className:\"code\",children:\"2536\"})]}),(0,e.jsx)(l.span,{className:\"error-behind\",children:\"Type 'T[keyof T]' cannot be used to index type 'Record'.\"}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsxs)(l[\"data-err\"],{children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[keyof T]\",children:\"groupedKey\"})]}),\"].\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"any\",children:\"push\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends object\",children:\"val\"}),\");\"]})]}),(0,e.jsxs)(l.span,{className:\"error\",children:[(0,e.jsx)(l.span,{children:\"Type 'T[keyof T]' cannot be used to index type 'Record'.\"}),(0,e.jsx)(l.span,{className:\"code\",children:\"2536\"})]}),(0,e.jsx)(l.span,{className:\"error-behind\",children:\"Type 'T[keyof T]' cannot be used to index type 'Record'.\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\";\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }, {} \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"as\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"string\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in sadAttempt(arr: T[], key: keyof T): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]>);\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"The lines with \",(0,e.jsx)(l.code,{children:\"accumulator[groupedKey]\"}),\" will error with \",(0,e.jsx)(l.code,{children:\"Type 'T[keyof T]' cannot be used to index type 'Record'\"}),\". Here the \",(0,e.jsx)(l.code,{children:\"keyof T\"}),\" could be any key in \",(0,e.jsx)(l.code,{children:\"T\"}),\" so since not every key's value in \",(0,e.jsx)(l.code,{children:\"T\"}),\" is a string typescript will not let you treat \",(0,e.jsx)(l.code,{children:\"groupedKey\"}),\" as a string.\"]}),`\n`,(0,e.jsx)(l.p,{children:\"We can almost fix this by adding some more information on the input key by binding it to a new generic parameter, though there will still be some issues.\"}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"function\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"betterSadAttempt\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type PropertyKey = string | number | symbol\",children:\"PropertyKey\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">, \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"Key\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">(\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[],\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: Key extends keyof T\",children:\"key\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"Key\"})})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\")\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"Key\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"], \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]> {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.reduce>(callbackfn: (previousValue: Record, currentValue: T, currentIndex: number, array: T[]) => Record, initialValue: Record<...>): Record<...> (+2 overloads)\",children:\"reduce\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"((\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\") \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=>\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: Key extends keyof T\",children:\"key\"}),\"];\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"if\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" (\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"!\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\"]) {\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\"] \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [];\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\"].\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.push(...items: T[]): number\",children:\"push\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"}),\");\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\";\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }, {} \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"as\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"Key\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"], \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in betterSadAttempt, Key extends keyof T>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]>);\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"Here we added a new generic \",(0,e.jsx)(l.code,{children:\"Key extends keyof T\"}),\" so when we supply a specific key to the function, the Key generic will be narrowed to that value. For example if we did \",(0,e.jsx)(l.code,{children:\"betterSadAttempt(vals, 'someLiteral')\"}),\", \",(0,e.jsx)(l.code,{children:\"Key\"}),\" would exactly be \",(0,e.jsx)(l.code,{children:\"'someLiteral'\"}),\" instead of \",(0,e.jsx)(l.code,{children:\"keyof Foo = 'someLiteral' | 'num' | 'object'\"})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"However, typescript is still sad on the \",(0,e.jsx)(l.code,{children:\"Record\"}),\" lines with \",(0,e.jsx)(l.code,{children:\"Type 'T[Key]' does not satisfy the constraint 'string | number | symbol'\"}),`.\nThis error is similar to the error before, basically `,(0,e.jsx)(l.code,{children:\"T[Key]\"}),\" can not be a key for the \",(0,e.jsx)(l.code,{children:\"Record\"}),\" since it could be some weird value.\"]}),`\n`,(0,e.jsxs)(l.p,{children:[\"To accomplish this we need to make a helper type that filters down the allowed keys to only keys whose values are \",(0,e.jsx)(l.code,{children:\"string | number | symbol\"}),`.\nWe can use a `,(0,e.jsx)(l.a,{href:\"https://www.typescriptlang.org/docs/handbook/2/mapped-types.html\",children:\"mapped type\"}),\" to do just that\"]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type MapValuesToKeysIfAllowed = { [K in keyof T]: T[K] extends PropertyKey ? K : never; }\",children:\"MapValuesToKeysIfAllowed\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type MapValuesToKeysIfAllowed\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"> \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) K\",children:\"K\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"in\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type MapValuesToKeysIfAllowed\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"]\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type MapValuesToKeysIfAllowed\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) K\",children:\"K\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"] \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type PropertyKey = string | number | symbol\",children:\"PropertyKey\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"?\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) K\",children:\"K\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"never\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"};\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Filter = MapValuesToKeysIfAllowed[keyof T]\",children:\"Filter\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"> \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type MapValuesToKeysIfAllowed = { [K in keyof T]: T[K] extends PropertyKey ? K : never; }\",children:\"MapValuesToKeysIfAllowed\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">[\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"];\"})]})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"This type helper does a few things. First it maps over all the values in \",(0,e.jsx)(l.code,{children:\"T\"}),\" (\",(0,e.jsx)(l.code,{children:\"[K in keyof T]\"}),\") and makes the value the key if it is a subset of \",(0,e.jsx)(l.code,{children:\"string | number | symbol\"}),\" (\",(0,e.jsx)(l.code,{children:\"T[K] extends PropertyKey ? K\"}),\"), if it's not a subset its value will be the \",(0,e.jsx)(l.code,{children:\"never\"}),\" type. Finally, we use an \",(0,e.jsx)(l.a,{href:\"https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html\",children:\"index access type\"}),\" to get all values of the transformed object as a union. This step will drop all the \",(0,e.jsx)(l.code,{children:\"never\"}),\" values automatically for us since adding \",(0,e.jsx)(l.code,{children:\"never\"}),\" to a union is like saying \",(0,e.jsx)(l.code,{children:\"or false\"}),\" its basically is a no op.\"]}),`\n`,(0,e.jsx)(l.p,{children:\"That was a mouthful so let's see an example\"}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// from above\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"interface\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Foo\",children:\"Foo\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.num: number\",children:\"num\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"number\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'(property) Foo.someLiteral: \"a\" | \"b\" | \"c\"',children:\"someLiteral\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"a\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"|\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"b\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"|\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"c\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) Foo.object: Record\",children:\"object\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"string\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:`type MappedFoo = {\n num: \"num\";\n someLiteral: \"someLiteral\";\n object: never;\n}`,children:\"MappedFoo\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type MapValuesToKeysIfAllowed = { [K in keyof T]: T[K] extends PropertyKey ? K : never; }\",children:\"MapValuesToKeysIfAllowed\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Foo\",children:\"Foo\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"/*\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"{\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:' num: \"num\";'})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:' someLiteral: \"someLiteral\";'})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" object: never;\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"*/\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// we replace the values of this object with just the key as a string literal or never\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:'type FooKeys = \"num\" | \"someLiteral\"',children:\"FooKeys\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Filter = MapValuesToKeysIfAllowed[keyof T]\",children:\"Filter\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface Foo\",children:\"Foo\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:'// => \"num\" | \"someLiteral\"'})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// notice the never does not show up in the union\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"interface\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface AllObjects\",children:\"AllObjects\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) AllObjects.object: Record\",children:\"object\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"string\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(property) AllObjects.diffObject: Record\",children:\"diffObject\"})]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"number\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:`type MappedAllObjects = {\n object: never;\n diffObject: never;\n}`,children:\"MappedAllObjects\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type MapValuesToKeysIfAllowed = { [K in keyof T]: T[K] extends PropertyKey ? K : never; }\",children:\"MapValuesToKeysIfAllowed\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface AllObjects\",children:\"AllObjects\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"/*\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"{ \"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" object: never;\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\" diffObject: never;\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"*/\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type AllObjectsKeys = never\",children:\"AllObjectsKeys\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Filter = MapValuesToKeysIfAllowed[keyof T]\",children:\"Filter\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"interface AllObjects\",children:\"AllObjects\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// => never\"})}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:'// the output is only never. Think of this like saying \"false or false\", the output will just be false'})})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"With this filter type helper function we can now properly limit the \",(0,e.jsx)(l.code,{children:\"Key\"}),\" generic by replacing \",(0,e.jsx)(l.code,{children:\"Key extends keyof T\"}),\" with \",(0,e.jsx)(l.code,{children:\"Key extends Filter\"}),\".\"]}),`\n`,(0,e.jsxs)(l.h2,{id:\"putting-it-all-together\",children:[(0,e.jsx)(l.a,{\"aria-hidden\":\"true\",tabIndex:\"-1\",href:\"#putting-it-all-together\",children:(0,e.jsx)(l.span,{className:\"icon icon-link\"})}),\"Putting it all together\"]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type MapValuesToKeysIfAllowed = { [K in keyof T]: T[K] extends PropertyKey ? K : never; }\",children:\"MapValuesToKeysIfAllowed\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type MapValuesToKeysIfAllowed\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"> \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) K\",children:\"K\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"in\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type MapValuesToKeysIfAllowed\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"]\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type MapValuesToKeysIfAllowed\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) K\",children:\"K\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"] \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type PropertyKey = string | number | symbol\",children:\"PropertyKey\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"?\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) K\",children:\"K\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"never\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"};\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Filter = MapValuesToKeysIfAllowed[keyof T]\",children:\"Filter\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"> \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type MapValuesToKeysIfAllowed = { [K in keyof T]: T[K] extends PropertyKey ? K : never; }\",children:\"MapValuesToKeysIfAllowed\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">[\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"];\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"function\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"groupBy\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type PropertyKey = string | number | symbol\",children:\"PropertyKey\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"any\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">, \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"Key\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Filter = MapValuesToKeysIfAllowed[keyof T]\",children:\"Filter\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">>(\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[],\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: Key extends Filter\",children:\"key\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"Key\"})})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\")\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"Key\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"], \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]> {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.reduce>(callbackfn: (previousValue: Record, currentValue: T, currentIndex: number, array: T[]) => Record, initialValue: Record<...>): Record<...> (+2 overloads)\",children:\"reduce\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"((\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\") \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=>\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) key: Key extends Filter\",children:\"key\"}),\"];\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"if\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" (\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"!\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\"]) {\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\"] \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [];\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: T[Key]\",children:\"groupedKey\"}),\"].\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.push(...items: T[]): number\",children:\"push\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T extends Record\",children:\"val\"}),\");\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\";\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }, {} \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"as\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) Key in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"Key\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"], \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupBy, Key extends Filter>(arr: T[], key: Key): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]>);\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const nums: Record\",children:\"nums\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:'function groupBy(arr: Foo[], key: \"num\"): Record',children:\"groupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"num\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\");\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// nums = Record\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'const literals: Record<\"a\" | \"b\" | \"c\", Foo[]>',children:\"literals\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:'function groupBy(arr: Foo[], key: \"someLiteral\"): Record<\"a\" | \"b\" | \"c\", Foo[]>',children:\"groupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"someLiteral\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\");\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:'// literals = Record<\"a\" | \"b\" | \"c\", Foo[]>'})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'const sad: Record',children:\"sad\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:'function groupBy>(arr: Foo[], key: Filter): Record',children:\"groupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"object\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\");\"})]}),(0,e.jsxs)(l.span,{className:\"error\",children:[(0,e.jsx)(l.span,{children:`Argument of type '\"object\"' is not assignable to parameter of type 'Filter'.`}),(0,e.jsx)(l.span,{className:\"code\",children:\"2345\"})]}),(0,e.jsx)(l.span,{className:\"error-behind\",children:`Argument of type '\"object\"' is not assignable to parameter of type 'Filter'.`})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[`Now this works great, we can only pass in keys that have valid values, and we even get autocomplete on it! However, one thing that bothers me is the error message in the last case.\nWhile it's correct, saying `,(0,e.jsx)(l.code,{children:\"not assignable to parameter of type 'Filter'\"}),\" is not very useful to a user. This pops up sometimes with typescript where it won't show the underlying type and instead just show the higher level type helper instead.\"]}),`\n`,(0,e.jsxs)(l.p,{children:[\"To make the error message show the valid keys we can use a modified version of \",(0,e.jsx)(l.a,{href:\"https://stackoverflow.com/a/57683652\",children:'this \"hack\"'}),\". Here instead of creating the \",(0,e.jsx)(l.code,{children:\"Expand\"}),\" type in the post, we can make our own \",(0,e.jsx)(l.code,{children:\"ValuesOf\"}),\" to replace the \",(0,e.jsx)(l.code,{children:\"[keyof T]\"}),\" at the end of \",(0,e.jsx)(l.code,{children:\"Filter\"})]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type ValuesOf = A extends infer O ? A[keyof A] : never\",children:\"ValuesOf\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) A in type ValuesOf\",children:\"A\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"> \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) A in type ValuesOf\",children:\"A\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"infer\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) O\",children:\"O\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"?\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) A in type ValuesOf\",children:\"A\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"keyof\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) A in type ValuesOf\",children:\"A\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"] \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:\"never\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\";\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"type\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Filter = MapValuesToKeysIfAllowed extends infer O ? (O & MapValuesToKeysIfAllowed)[keyof T | keyof O] : never\",children:\"Filter\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"> \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type ValuesOf = A extends infer O ? A[keyof A] : never\",children:\"ValuesOf\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type MapValuesToKeysIfAllowed = { [K in keyof T]: T[K] extends PropertyKey ? K : never; }\",children:\"MapValuesToKeysIfAllowed\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in type Filter\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">>;\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// was Filter = MapValuesToKeysIfAllowed[keyof T]\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:'const sad: Record',children:\"sad\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:'function groupBy(arr: Foo[], key: \"num\" | \"someLiteral\"): Record',children:\"groupBy\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const vals: Foo[]\",children:\"vals\"}),\", \"]}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F1FA8C\"},children:\"object\"}),(0,e.jsx)(l.span,{style:{color:\"#E9F284\"},children:\"'\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\");\"})]}),(0,e.jsxs)(l.span,{className:\"error\",children:[(0,e.jsx)(l.span,{children:`Argument of type '\"object\"' is not assignable to parameter of type '\"num\" | \"someLiteral\"'.`}),(0,e.jsx)(l.span,{className:\"code\",children:\"2345\"})]}),(0,e.jsx)(l.span,{className:\"error-behind\",children:`Argument of type '\"object\"' is not assignable to parameter of type '\"num\" | \"someLiteral\"'.`})]})})]}),`\n`,(0,e.jsx)(l.p,{children:\"Now we have type safety and good error messages!\"}),`\n`,(0,e.jsxs)(l.h2,{id:\"possible-improvements\",children:[(0,e.jsx)(l.a,{\"aria-hidden\":\"true\",tabIndex:\"-1\",href:\"#possible-improvements\",children:(0,e.jsx)(l.span,{className:\"icon icon-link\"})}),\"Possible improvements\"]}),`\n`,(0,e.jsxs)(l.p,{children:[\"One thing this \",(0,e.jsx)(l.code,{children:\"groupBy\"}),\" function lacks that the lodash \",(0,e.jsx)(l.code,{children:\"groupBy\"}),` gives is we do not allow you to pass a function instead of a key to group on.\nThe example in the lodash docs is`]}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:`(alias) namespace _\n(alias) const _: import(\"/home/runner/work/JRMurr.github.io/JRMurr.github.io/node_modules/@types/lodash/index.d.ts\").LoDashStatic\nimport _`,children:\"_\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) LoDashStatic.groupBy(collection: _.List | null | undefined, iteratee?: _.ValueIteratee | undefined): _.Dictionary (+1 overload)\",children:\"groupBy\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"([\"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"6.1\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"4.2\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"6.3\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"], \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"var Math: Math\",children:\"Math\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\".\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Math.floor(x: number): number\",children:\"floor\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\");\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// { '4': [4.2], '6': [6.1, 6.3] }\"})})]})})]}),`\n`,(0,e.jsx)(l.p,{children:\"While this is not perfect this mostly works\"}),`\n`,(0,e.jsxs)(l.pre,{className:\"shiki dracula twoslash lsp\",style:{backgroundColor:\"#282A36\",color:\"#F8F8F2\"},children:[(0,e.jsx)(l.div,{className:\"language-id\",children:\"ts\"}),(0,e.jsx)(l.div,{className:\"code-container\",children:(0,e.jsxs)(l.code,{children:[(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"function\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function groupByFunc(arr: T[], mapper: (arg: T) => RetType): Record\",children:\"groupByFunc\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) RetType in groupByFunc(arr: T[], mapper: (arg: T) => RetType): Record\",children:\"RetType\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"extends\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type PropertyKey = string | number | symbol\",children:\"PropertyKey\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\",\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupByFunc(arr: T[], mapper: (arg: T) => RetType): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// no longer need any requirements on T since the grouper can do w/e it wants\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\">(\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupByFunc(arr: T[], mapper: (arg: T) => RetType): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[], \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) mapper: (arg: T) => RetType\",children:\"mapper\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" (\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arg: T\",children:\"arg\"})}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupByFunc(arr: T[], mapper: (arg: T) => RetType): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\") \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=>\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) RetType in groupByFunc(arr: T[], mapper: (arg: T) => RetType): Record\",children:\"RetType\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\")\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\":\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) RetType in groupByFunc(arr: T[], mapper: (arg: T) => RetType): Record\",children:\"RetType\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupByFunc(arr: T[], mapper: (arg: T) => RetType): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]> {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) arr: T[]\",children:\"arr\"}),\".\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.reduce>(callbackfn: (previousValue: Record, currentValue: T, currentIndex: number, array: T[]) => Record, initialValue: Record<...>): Record<...> (+2 overloads)\",children:\"reduce\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"((\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T\",children:\"val\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\") \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=>\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" {\"})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: RetType extends PropertyKey\",children:\"groupedKey\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) mapper: (arg: T) => RetType\",children:\"mapper\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T\",children:\"val\"}),\");\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"if\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" (\"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"!\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: RetType extends PropertyKey\",children:\"groupedKey\"}),\"]) {\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: RetType extends PropertyKey\",children:\"groupedKey\"}),\"] \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" [];\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }\"})}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\"[\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const groupedKey: RetType extends PropertyKey\",children:\"groupedKey\"}),\"].\"]}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Array.push(...items: T[]): number\",children:\"push\"})}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\"(\",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) val: T\",children:\"val\"}),\");\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"return\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(parameter) accumulator: Record\",children:\"accumulator\"}),\";\"]})]}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" }, {} \"}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"as\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"type Record = { [P in K]: T; }\",children:\"Record\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"<\"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) RetType in groupByFunc(arr: T[], mapper: (arg: T) => RetType): Record\",children:\"RetType\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#FFB86C\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(type parameter) T in groupByFunc(arr: T[], mapper: (arg: T) => RetType): Record\",children:\"T\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"[]>);\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"}\"})}),(0,e.jsx)(l.div,{className:\"line\",children:\"\\xA0\"}),(0,e.jsxs)(l.div,{className:\"line\",children:[(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"const\"}),(0,e.jsxs)(l.span,{style:{color:\"#F8F8F2\"},children:[\" \",(0,e.jsx)(l[\"data-lsp\"],{lsp:\"const test: Record\",children:\"test\"}),\" \"]}),(0,e.jsx)(l.span,{style:{color:\"#FF79C6\"},children:\"=\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\" \"}),(0,e.jsx)(l.span,{style:{color:\"#50FA7B\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"function groupByFunc(arr: number[], mapper: (arg: number) => number): Record\",children:\"groupByFunc\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"([\"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"6.1\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"4.2\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\", \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:\"6.3\"}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\"], \"}),(0,e.jsx)(l.span,{style:{color:\"#BD93F9\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"var Math: Math\",children:\"Math\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\".\"}),(0,e.jsx)(l.span,{style:{color:\"#8BE9FD\"},children:(0,e.jsx)(l[\"data-lsp\"],{lsp:\"(method) Math.floor(x: number): number\",children:\"floor\"})}),(0,e.jsx)(l.span,{style:{color:\"#F8F8F2\"},children:\");\"})]}),(0,e.jsx)(l.div,{className:\"line\",children:(0,e.jsx)(l.span,{style:{color:\"#6272A4\"},children:\"// test = Record\"})})]})})]}),`\n`,(0,e.jsxs)(l.p,{children:[\"This works by only letting you pass in functions that return \",(0,e.jsx)(l.code,{children:\"PropertyKey\"}),\", and typescript even narrows the types. In this case \",(0,e.jsx)(l.code,{children:\"test\"}),\" is \",(0,e.jsx)(l.code,{children:\"Record\"}),\" since TS infers the return type of the grouping function.\"]}),`\n`,(0,e.jsxs)(l.p,{children:[\"If you know how to improve this function further feel free to leave an issue/pr on my \",(0,e.jsx)(l.a,{href:\"https://github.com/JRMurr/JRMurr.github.io\",children:\"blog's GitHub\"}),\"!\"]})]})}}var b=g;function C(r,s){throw new Error(\"Expected \"+(s?\"component\":\"object\")+\" `\"+r+\"` to be defined: you likely forgot to import, pass, or provide it.\")}return f;})();\n;return Component;","toc":[{"value":"Lodash's groupBy","url":"#lodashs-groupby","depth":2},{"value":"Making our own groupBy","url":"#making-our-own-groupby","depth":2},{"value":"Putting it all together","url":"#putting-it-all-together","depth":2},{"value":"Possible improvements","url":"#possible-improvements","depth":2}],"frontMatter":{"readingTime":{"text":"16 min read","minutes":15.520833333333334,"time":931250,"words":3725},"slug":"type-safe-groupby-in-typescript","fileName":"type-safe-groupby-in-typescript.md","title":"Type Safe GroupBy In TypeScript","date":"2022-05-25T00:00:00.000Z","tags":["typescript","types","code","guide"],"draft":false,"summary":"Create a better groupBy function that only allows valid keys to be grouped on","images":[],"layout":"PostLayout"}},"authorDetails":[{"readingTime":{"text":"1 min read","minutes":0.17916666666666667,"time":10750,"words":43},"slug":["default"],"fileName":"default.md","name":"John Murray","avatar":"/static/images/me.jpg","occupation":"Software Engineer","github":"https://github.com/JRMurr","twitter":"https://twitter.com/JRMurrCodes","mastodon":"https://hachyderm.io/@jrmurr","email":"johnreillymurray@gmail.com","date":null}],"series":null},"__N_SSG":true} \ No newline at end of file diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/blog/updating-a-package-in-nixpkgs.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/updating-a-package-in-nixpkgs.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/blog/updating-a-package-in-nixpkgs.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/blog/updating-a-package-in-nixpkgs.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/index.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/index.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/index.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/index.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags/code.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/code.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags/code.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/code.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags/database.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/database.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags/database.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/database.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags/docker.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/docker.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags/docker.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/docker.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags/dotfiles.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/dotfiles.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags/dotfiles.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/dotfiles.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags/guide.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/guide.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags/guide.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/guide.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags/nix-pkgs.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/nix-pkgs.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags/nix-pkgs.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/nix-pkgs.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags/nix.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/nix.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags/nix.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/nix.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags/nixos.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/nixos.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags/nixos.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/nixos.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags/node.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/node.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags/node.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/node.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags/parsing.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/parsing.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags/parsing.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/parsing.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags/repl.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/repl.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags/repl.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/repl.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags/roc.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/roc.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags/roc.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/roc.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags/rust.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/rust.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags/rust.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/rust.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags/types.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/types.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags/types.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/types.json diff --git a/_next/data/_FHim0G2RtBJmEIVqQhwr/tags/typescript.json b/_next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/typescript.json similarity index 100% rename from _next/data/_FHim0G2RtBJmEIVqQhwr/tags/typescript.json rename to _next/data/Uq4sBV3BGaoHG9usvVJ-V/tags/typescript.json diff --git a/_next/static/_FHim0G2RtBJmEIVqQhwr/_buildManifest.js b/_next/static/Uq4sBV3BGaoHG9usvVJ-V/_buildManifest.js similarity index 100% rename from _next/static/_FHim0G2RtBJmEIVqQhwr/_buildManifest.js rename to _next/static/Uq4sBV3BGaoHG9usvVJ-V/_buildManifest.js diff --git a/_next/static/_FHim0G2RtBJmEIVqQhwr/_middlewareManifest.js b/_next/static/Uq4sBV3BGaoHG9usvVJ-V/_middlewareManifest.js similarity index 100% rename from _next/static/_FHim0G2RtBJmEIVqQhwr/_middlewareManifest.js rename to _next/static/Uq4sBV3BGaoHG9usvVJ-V/_middlewareManifest.js diff --git a/_next/static/_FHim0G2RtBJmEIVqQhwr/_ssgManifest.js b/_next/static/Uq4sBV3BGaoHG9usvVJ-V/_ssgManifest.js similarity index 100% rename from _next/static/_FHim0G2RtBJmEIVqQhwr/_ssgManifest.js rename to _next/static/Uq4sBV3BGaoHG9usvVJ-V/_ssgManifest.js diff --git a/about.html b/about.html index d7f6f86..571760f 100644 --- a/about.html +++ b/about.html @@ -1 +1 @@ -About - John Murray

About

avatar

John Murray

Software Engineer

Will ramble on types, rust, and nix as much as humanely possible.

\ No newline at end of file +About - John Murray

About

avatar

John Murray

Software Engineer

Will ramble on types, rust, and nix as much as humanely possible.

\ No newline at end of file diff --git a/blog.html b/blog.html index 45d90b0..8a43390 100644 --- a/blog.html +++ b/blog.html @@ -1 +1 @@ -Blog - John Murray

All Posts

\ No newline at end of file +Blog - John Murray

All Posts

\ No newline at end of file diff --git a/blog/build-a-db/part01.html b/blog/build-a-db/part01.html index 3b27c7f..485098a 100644 --- a/blog/build-a-db/part01.html +++ b/blog/build-a-db/part01.html @@ -29,7 +29,7 @@ } }, "description": "building a basic database in rust" -}
Published on
-
13 min read

Building a Simple DB in Rust - Part 1 - Parsing

This article is part of the Building a Simple DB in Rust series.

Table of Contents
+}
Published on
-
13 min read

Building a Simple DB in Rust - Part 1 - Parsing

This article is part of the Building a Simple DB in Rust series.

Table of Contents

While I've used rust for a while and have had a few small projects in it, I felt like I was missing a truly "systems" project. So when I came across this series for making a simple DB in C, I figured why not try to make my basic DB in rust. I will roughly follow the structure of that series at first, but I will most likely deviate and focus on what interests me more.

@@ -185,4 +185,4 @@

Part 1 wrap up

I definitely went overkill (but still feels like not enough...) on getting the parser errors to work nicely, but our eventual 0 users will appreciate it.

-

Next post will focus on actually running queries (and addressing any feedback I get on this post).

\ No newline at end of file +

Next post will focus on actually running queries (and addressing any feedback I get on this post).

\ No newline at end of file diff --git a/blog/build-a-db/part02.html b/blog/build-a-db/part02.html index ced0e03..8ab1064 100644 --- a/blog/build-a-db/part02.html +++ b/blog/build-a-db/part02.html @@ -29,7 +29,7 @@ } }, "description": "Building a basic database in rust" -}
Published on
-
10 min read

Building a Simple DB in Rust - Part 2 - Basic Execution

This article is part of the Building a Simple DB in Rust series.

Table of Contents
+}
Published on
-
10 min read

Building a Simple DB in Rust - Part 2 - Basic Execution

This article is part of the Building a Simple DB in Rust series.

Table of Contents

Feedback from part 1

I got some very nice feedback from the first part of this series. The main suggestions were to use some different parsing libraries like chumsky or use an existing SQL parser like sqlparser-rs.

chumsky looks like it handles a lot of the error handling logic I had to do myself while still being defined in rust (no extra language). If I had known of this before I would have used it. Might switch to it later on if our grammar gets more involved. Thanks @hjvt@hachyderm.io for the recommendation!

@@ -131,4 +131,4 @@

{columns: Rc<ColumnInfo>, row: Vec<Row>}

but I'll save that for the next post.

Wrap up

-

Having basic execution feels nice, but the real challenge will be filtering and projecting the data. We have some extra clones and unwraps/expects we need to handle once we start moving away from this extremely simple happy path but so far the high level design feels good!

\ No newline at end of file +

Having basic execution feels nice, but the real challenge will be filtering and projecting the data. We have some extra clones and unwraps/expects we need to handle once we start moving away from this extremely simple happy path but so far the high level design feels good!

\ No newline at end of file diff --git a/blog/build-a-db/part03.html b/blog/build-a-db/part03.html index a72bb1a..a6421bf 100644 --- a/blog/build-a-db/part03.html +++ b/blog/build-a-db/part03.html @@ -29,7 +29,7 @@ } }, "description": "Cleaning up existing execution logic" -}
Published on
-
6 min read

Building a Simple DB in Rust - Part 3 - Less Basic Execution

This article is part of the Building a Simple DB in Rust series.

Table of Contents
+}
Published on
-
6 min read

Building a Simple DB in Rust - Part 3 - Less Basic Execution

This article is part of the Building a Simple DB in Rust series.

Table of Contents

Where we left off

In the last post we ended up with extremely basic query execution. We could parse queries, update our tables in memory, and read full tables back; all while having decent error messages throughout.

@@ -105,4 +105,4 @@

\ No newline at end of file +

If you really want some more I would highly recommend trying this yourself! As you can probably tell from reading this posts, I'm far from a DB expert. Just start somewhere, you would be impressed with how much you can accomplish already and how much you will learn as you go!

\ No newline at end of file diff --git a/blog/building-typescript-node-apps-with-nix.html b/blog/building-typescript-node-apps-with-nix.html index 572261a..6386bb4 100644 --- a/blog/building-typescript-node-apps-with-nix.html +++ b/blog/building-typescript-node-apps-with-nix.html @@ -29,7 +29,7 @@ } }, "description": "Trying some different nix builders for typescript node apps" -}
Published on
-
11 min read

Building Typescript Node Apps With Nix

Table of Contents
+}
Published on
-
11 min read

Building Typescript Node Apps With Nix

Table of Contents

Being a Nix Stan

I recently accepted that I am obsessed with Nix. Ask any remotely technical person with a pulse, and they can probably mention at least 10 times I've told them "But with nix X is way easier/a nonissue" (same with rust, but that's for another day...).

The issue is, that I am a bit of a poser. I've been using Nix on/off for about 2.5 years but only seriously for the last 10ish months. @@ -173,4 +173,4 @@

here for some more info on nix docker builds.

\ No newline at end of file +

You can then run nix build .#docker and then run docker load < result to load the image into docker. See here for some more info on nix docker builds.

\ No newline at end of file diff --git a/blog/efficient-nix-derivations-with-file-sets.html b/blog/efficient-nix-derivations-with-file-sets.html index 17107bd..3aa23d5 100644 --- a/blog/efficient-nix-derivations-with-file-sets.html +++ b/blog/efficient-nix-derivations-with-file-sets.html @@ -29,7 +29,7 @@ } }, "description": "Using nix's new file set API to make efficient derivations" -}
Published on
-
6 min read

Efficient Nix Derivations with File Sets

Table of Contents
+}
Published on
-
6 min read

Efficient Nix Derivations with File Sets

Table of Contents

If you are using Nix to build your own packages you will eventually come across something like

nix
stdenv.mkDerivation {
name = "my awesome pkg";
src = ./.;
buildPhase = ''
# I have no idea if this actually works (the gcc call bit)
# but the vibe is what I care about
gcc main.c -o my_program
mkdir -p $out
cp my_program $out
'';
}

The issue with the above is setting src = ./., which makes ALL of the current directory an input to the derivation. @@ -78,4 +78,4 @@

to develop this feature!

I hope filesets make more people take a stab at making their own *2nix builders, or just make their own builds more efficent.

I had a lot of fun working on roc2nix, it was my first time making a "real" nix library and I learned a lot along the way (not just file sets). -If you are interested in learning more about it check out the repo or let me know in the comments and I might make a separate blog diving into that (and hopefully some blogs on roc itself).

\ No newline at end of file +If you are interested in learning more about it check out the repo or let me know in the comments and I might make a separate blog diving into that (and hopefully some blogs on roc itself).

\ No newline at end of file diff --git a/blog/exposing-a-rust-library-to-node-with-napirs.html b/blog/exposing-a-rust-library-to-node-with-napirs.html index 9b4aef9..c5e95af 100644 --- a/blog/exposing-a-rust-library-to-node-with-napirs.html +++ b/blog/exposing-a-rust-library-to-node-with-napirs.html @@ -29,7 +29,7 @@ } }, "description": "Short guide/exploration on making native node addons with rust" -}
Published on
-
9 min read

Exposing a Rust Library to Node with Napi-rs

Table of Contents
+}
Published on
-
9 min read

Exposing a Rust Library to Node with Napi-rs

Table of Contents

I unapologetically shill Rust every chance I get, annoying my coworkers by insisting that everything would be better if we just used Rust. At this point, it has become a bit of a meme, so no one listens to me (rightfully so).

To finally put an end to the meme, I decided to research ways we could incorporate Rust into our systems. Ideally, we would create a new service in Rust, but since we are not yet big on microservices, the best approach would be to call Rust directly from our Node monolith.

Since Node is written in C++, it provides ways to call native code via addons. The napi-rs library helps with the boilerplate of exposing Rust code as a Node addon.

@@ -112,4 +112,4 @@

experimental JS generator support (with no docs on it that I can find), and no support for async generators/node streams. While you could manually add JS code to support these would be much nicer if napi did it for you. Stream support is planned for v3, so hopefully the others will follow.

Wrap up

Overall napi is very useable and with my limited use of cross-language FFI tools, it has had the nicest user experience. -While it has limitations/some issues overall nothing major is in your way from exposing very useable and performant code if you put in a little extra work.

\ No newline at end of file +While it has limitations/some issues overall nothing major is in your way from exposing very useable and performant code if you put in a little extra work.

\ No newline at end of file diff --git a/blog/intermediate-typescript-generics-and-mapped-types.html b/blog/intermediate-typescript-generics-and-mapped-types.html index 9d9f6b2..662938a 100644 --- a/blog/intermediate-typescript-generics-and-mapped-types.html +++ b/blog/intermediate-typescript-generics-and-mapped-types.html @@ -29,7 +29,7 @@ } }, "description": "Useful applications of generics and mapped types" -}
Published on
-
12 min read

Intermediate Typescript: Generics and Mapped Types

Table of Contents
+}
Published on
-
12 min read

Intermediate Typescript: Generics and Mapped Types

Table of Contents

In the last post, I covered Literal and Union types. Those types are great and can get you a long way when writing your apps. When your codebase starts to grow you may find your middleware/helper functions still have too general of types which leads to more type casting than you would like. This is where generics and mapped types come in.

Generics

If your first interaction with generics was with java in school they may have put a bad taste in your mouth. @@ -166,4 +166,4 @@

Wrap up

-

Generics and Mapped Types are extremely powerful tools to help types follow through your program and to avoid repeating yourself. They can be a little confusing to newcomers so be sure to comment them well.

\ No newline at end of file +

Generics and Mapped Types are extremely powerful tools to help types follow through your program and to avoid repeating yourself. They can be a little confusing to newcomers so be sure to comment them well.

\ No newline at end of file diff --git a/blog/intermediate-typescript.html b/blog/intermediate-typescript.html index 03650b9..4b54cae 100644 --- a/blog/intermediate-typescript.html +++ b/blog/intermediate-typescript.html @@ -29,7 +29,7 @@ } }, "description": "Typescript patterns I have found to make your life easier in a big codebase" -}
Published on
-
8 min read

Intermediate Typescript: Literals and Unions

Table of Contents
+}
Published on
-
8 min read

Intermediate Typescript: Literals and Unions

Table of Contents

At my job we have spent a lot of time converting a node backend and angular frontend to Typescript. Before Typescript when working in our codebase I found myself having to read a lot of code, API schemas, and tests just to see what fields actually existed. So during the transition I tried my hardest to make the types I made as descriptive as they could be. @@ -92,4 +92,4 @@

Wrap up

While these features I covered can help you a lot (these are almost all I used during the initial typescript migration), there are many other really cool typescript features, like generics, mapped types and conditional types. -I hope to cover them all in a Part 2 so check back soon!

\ No newline at end of file +I hope to cover them all in a Part 2 so check back soon!

\ No newline at end of file diff --git a/blog/organizing-system-configs-with-nixos.html b/blog/organizing-system-configs-with-nixos.html index 3bca1d6..df3af94 100644 --- a/blog/organizing-system-configs-with-nixos.html +++ b/blog/organizing-system-configs-with-nixos.html @@ -29,7 +29,7 @@ } }, "description": "How I organize and manage my system and user configs with NixOS and homemanager" -}
Published on
-
15 min read

Organizing system configs with NixOS

Table of Contents
+}
Published on
-
15 min read

Organizing system configs with NixOS

Table of Contents

Nix and NixOS has been the technology I've been the most excited about in the last few years. While I have used Linux on my personal desktop and home server in the past, I never did anything complicated. It was so hard to remember what I did to my system to get it to work the way I wanted. @@ -172,4 +172,4 @@

Wrap up

NixOS + Home Manager feels like something from the future (even though nix is like 20 years old....). The freedom you have to change and experiment is amazing. I didn't even go into some other awesome features like system rollback, distributed builds, and making your own configuration options.

-

If you want to give NixOS a shot I think my config is hopefully easy to follow. Leave a comment if you want any help!

\ No newline at end of file +

If you want to give NixOS a shot I think my config is hopefully easy to follow. Leave a comment if you want any help!

\ No newline at end of file diff --git a/blog/page/1.html b/blog/page/1.html index f2be976..c8312ae 100644 --- a/blog/page/1.html +++ b/blog/page/1.html @@ -1 +1 @@ -John's Codes

All Posts

\ No newline at end of file +John's Codes

All Posts

\ No newline at end of file diff --git a/blog/page/2.html b/blog/page/2.html index 73f9eeb..2d5f765 100644 --- a/blog/page/2.html +++ b/blog/page/2.html @@ -1 +1 @@ -John's Codes

All Posts

\ No newline at end of file +John's Codes

All Posts

\ No newline at end of file diff --git a/blog/page/3.html b/blog/page/3.html index 4aa194c..8e68b98 100644 --- a/blog/page/3.html +++ b/blog/page/3.html @@ -1 +1 @@ -John's Codes

All Posts

\ No newline at end of file +John's Codes

All Posts

\ No newline at end of file diff --git a/blog/rust-enviorment-and-docker-build-with-nix-flakes.html b/blog/rust-enviorment-and-docker-build-with-nix-flakes.html index 56bbce5..346223d 100644 --- a/blog/rust-enviorment-and-docker-build-with-nix-flakes.html +++ b/blog/rust-enviorment-and-docker-build-with-nix-flakes.html @@ -29,7 +29,7 @@ } }, "description": "Reproducible dev environments and builds with Nix" -}
Published on
-
8 min read

Rust Environment and Docker Build with Nix Flakes

Table of Contents
+}
Published on
-
8 min read

Rust Environment and Docker Build with Nix Flakes

Table of Contents

Why Nix

Getting a dev environment setup with rust is usually pretty simple, just use rustup then you're good to go. Using a build tool like Nix can buy you much more for not much extra work. Nix lets you

@@ -132,4 +132,4 @@

Intro to nix flakes Great 3 part series on what flakes are and how to use them
  • Building docker containers with nix Linked this earlier, but it's a good reference for more options on building containers
  • -

    I also highly recommend on diving headfirst into nix by using Nixos as your Linux distro. It will help make you more comfortable with the language and its great to use once it clicks.

    \ No newline at end of file +

    I also highly recommend on diving headfirst into nix by using Nixos as your Linux distro. It will help make you more comfortable with the language and its great to use once it clicks.

    \ No newline at end of file diff --git a/blog/type-safe-groupby-in-typescript.html b/blog/type-safe-groupby-in-typescript.html index 8d60319..4c0e109 100644 --- a/blog/type-safe-groupby-in-typescript.html +++ b/blog/type-safe-groupby-in-typescript.html @@ -29,7 +29,7 @@ } }, "description": "Create a better groupBy function that only allows valid keys to be grouped on" -}
    Published on
    -
    16 min read

    Type Safe GroupBy In TypeScript

    Table of Contents
    +}
    Published on
    -
    16 min read

    Type Safe GroupBy In TypeScript

    Table of Contents

    Lodash's groupBy

    I would bet if you have a sizeable Javascript/Typescript codebase you most likely are using lodash somewhere in there. While Javascript has gotten more "batteries included" over the last few years, lodash still has many nice functions for manipulating arrays/objects. @@ -96,6 +96,6 @@

    _.groupBy([6.1, 4.2, 6.3], Math.floor);

    While this is not perfect this mostly works

    -
    ts
    function groupByFunc<
    RetType extends PropertyKey,
    T, // no longer need any requirements on T since the grouper can do w/e it wants
    Func extends (arg: T) => RetType
    >(arr: T[], mapper: Func): Record<RetType, T[]> {
    return arr.reduce((accumulator, val) => {
    const groupedKey = mapper(val);
    if (!accumulator[groupedKey]) {
    accumulator[groupedKey] = [];
    }
    accumulator[groupedKey].push(val);
    return accumulator;
    }, {} as Record<RetType, T[]>);
    }
     
    const test = groupByFunc([6.1, 4.2, 6.3], Math.floor);
    // test = Record<PropertyKey, Foo[]>
    -

    This works by only letting you pass in functions that return PropertyKey, but typescript does not seem to narrow the types. In this case test should be Record<number, Foo[]> since TS should infer the return type of the grouping function. If you know how to improve this function to make the return type narrow properly feel free to leave an issue/pr on my blog's GitHub!

    \ No newline at end of file +
    ts
    function groupByFunc<
    RetType extends PropertyKey,
    T // no longer need any requirements on T since the grouper can do w/e it wants
    >(arr: T[], mapper: (arg: T) => RetType): Record<RetType, T[]> {
    return arr.reduce((accumulator, val) => {
    const groupedKey = mapper(val);
    if (!accumulator[groupedKey]) {
    accumulator[groupedKey] = [];
    }
    accumulator[groupedKey].push(val);
    return accumulator;
    }, {} as Record<RetType, T[]>);
    }
     
    const test = groupByFunc([6.1, 4.2, 6.3], Math.floor);
    // test = Record<PropertyKey, Foo[]>
    +

    This works by only letting you pass in functions that return PropertyKey, and typescript even narrows the types. In this case test is Record<number, Foo[]> since TS infers the return type of the grouping function.

    +

    If you know how to improve this function further feel free to leave an issue/pr on my blog's GitHub!

    \ No newline at end of file diff --git a/blog/updating-a-package-in-nixpkgs.html b/blog/updating-a-package-in-nixpkgs.html index 92943b3..763cf93 100644 --- a/blog/updating-a-package-in-nixpkgs.html +++ b/blog/updating-a-package-in-nixpkgs.html @@ -29,7 +29,7 @@ } }, "description": "My rough ramblings on how to contribute a small pr to Nixpkgs" -}
    Published on
    -
    4 min read

    Making a PR to Nixpkgs

    Why

    +}
    Published on
    -
    4 min read

    Making a PR to Nixpkgs

    Why

    Rust-analyzer was updated recently to better support proc macros when working on nightly rust versions. I wanted to use this change right away but since I use NixOS I needed the nix pkg repo to update its version of rust-analyzer, so I can use it properly.

    Edit: You don't need to make a pr to Nixpkgs just to update a version, they are other ways such as using overlays. Majiir on reddit goes over some options here

    @@ -85,4 +85,4 @@

    Profit

    You have now joined the ranks of thankless open source developers! Feel free to enjoy the dopamine of the PR being merged.

    If you want some more nix posts I recently wrote a blog for my job on how to setup simple nix flakes.

    -

    IF you would like a more in depth video walking through this process this video by Jon Ringer is quite good!

    \ No newline at end of file +

    IF you would like a more in depth video walking through this process this video by Jon Ringer is quite good!

    \ No newline at end of file diff --git a/index.html b/index.html index 88b6395..75efa5a 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ -John's Codes

    Latest

    \ No newline at end of file +John's Codes

    Latest

    \ No newline at end of file diff --git a/projects.html b/projects.html index 84e5574..6405357 100644 --- a/projects.html +++ b/projects.html @@ -1,2 +1,2 @@ -Projects - John Murray

    Projects

    SqlJr

    SqlJr

    A toy database to learn more lower level rust.

    Learn more →
    ThiccBot

    ThiccBot

    My custom discord bot I have re-made about 4 times now. - Its been a great project to come back to when I get the urge to make a small new thing.

    Learn more →
    \ No newline at end of file +Projects - John Murray

    Projects

    SqlJr

    SqlJr

    A toy database to learn more lower level rust.

    Learn more →
    ThiccBot

    ThiccBot

    My custom discord bot I have re-made about 4 times now. + Its been a great project to come back to when I get the urge to make a small new thing.

    Learn more →
    \ No newline at end of file diff --git a/tags.html b/tags.html index 5bc12c0..8ac5ef7 100644 --- a/tags.html +++ b/tags.html @@ -1 +1 @@ -Tags - John Murray \ No newline at end of file +Tags - John Murray \ No newline at end of file diff --git a/tags/code.html b/tags/code.html index cbbcead..ce3459a 100644 --- a/tags/code.html +++ b/tags/code.html @@ -1 +1 @@ -code - John's Codes

    Code

    \ No newline at end of file +code - John's Codes

    Code

    \ No newline at end of file diff --git a/tags/database.html b/tags/database.html index c72a3bb..7b6289b 100644 --- a/tags/database.html +++ b/tags/database.html @@ -1 +1 @@ -database - John's Codes

    Database

    \ No newline at end of file +database - John's Codes

    Database

    \ No newline at end of file diff --git a/tags/docker.html b/tags/docker.html index d327ab5..9606625 100644 --- a/tags/docker.html +++ b/tags/docker.html @@ -1 +1 @@ -docker - John's Codes

    Docker

    \ No newline at end of file +docker - John's Codes

    Docker

    \ No newline at end of file diff --git a/tags/dotfiles.html b/tags/dotfiles.html index e8bae9f..9317fce 100644 --- a/tags/dotfiles.html +++ b/tags/dotfiles.html @@ -1 +1 @@ -dotfiles - John's Codes

    Dotfiles

    \ No newline at end of file +dotfiles - John's Codes

    Dotfiles

    \ No newline at end of file diff --git a/tags/guide.html b/tags/guide.html index 8f375fe..bf3b75a 100644 --- a/tags/guide.html +++ b/tags/guide.html @@ -1 +1 @@ -guide - John's Codes

    Guide

    \ No newline at end of file +guide - John's Codes

    Guide

    \ No newline at end of file diff --git a/tags/nix-pkgs.html b/tags/nix-pkgs.html index da1e5e1..80bbfbd 100644 --- a/tags/nix-pkgs.html +++ b/tags/nix-pkgs.html @@ -1 +1 @@ -nix-pkgs - John's Codes

    Nix-pkgs

    \ No newline at end of file +nix-pkgs - John's Codes

    Nix-pkgs

    \ No newline at end of file diff --git a/tags/nix.html b/tags/nix.html index 10d912e..b96e447 100644 --- a/tags/nix.html +++ b/tags/nix.html @@ -1 +1 @@ -nix - John's Codes

    Nix

    \ No newline at end of file +nix - John's Codes

    Nix

    \ No newline at end of file diff --git a/tags/nixos.html b/tags/nixos.html index 1419853..5dc416a 100644 --- a/tags/nixos.html +++ b/tags/nixos.html @@ -1 +1 @@ -nixos - John's Codes

    Nixos

    \ No newline at end of file +nixos - John's Codes

    Nixos

    \ No newline at end of file diff --git a/tags/node.html b/tags/node.html index ad6d888..d0dd7e3 100644 --- a/tags/node.html +++ b/tags/node.html @@ -1 +1 @@ -node - John's Codes

    Node

    \ No newline at end of file +node - John's Codes

    Node

    \ No newline at end of file diff --git a/tags/parsing.html b/tags/parsing.html index 7b67042..a61c221 100644 --- a/tags/parsing.html +++ b/tags/parsing.html @@ -1 +1 @@ -parsing - John's Codes \ No newline at end of file +parsing - John's Codes \ No newline at end of file diff --git a/tags/repl.html b/tags/repl.html index 32176d8..ea53885 100644 --- a/tags/repl.html +++ b/tags/repl.html @@ -1 +1 @@ -repl - John's Codes \ No newline at end of file +repl - John's Codes \ No newline at end of file diff --git a/tags/roc.html b/tags/roc.html index a232f85..5411ace 100644 --- a/tags/roc.html +++ b/tags/roc.html @@ -1 +1 @@ -roc - John's Codes

    Roc

    \ No newline at end of file +roc - John's Codes

    Roc

    \ No newline at end of file diff --git a/tags/rust.html b/tags/rust.html index 6d7b747..9e1c536 100644 --- a/tags/rust.html +++ b/tags/rust.html @@ -1 +1 @@ -rust - John's Codes

    Rust

    \ No newline at end of file +rust - John's Codes

    Rust

    \ No newline at end of file diff --git a/tags/types.html b/tags/types.html index f628bcb..6590d9e 100644 --- a/tags/types.html +++ b/tags/types.html @@ -1 +1 @@ -types - John's Codes

    Types

    \ No newline at end of file +types - John's Codes

    Types

    \ No newline at end of file diff --git a/tags/typescript.html b/tags/typescript.html index 05923e7..e3f66bc 100644 --- a/tags/typescript.html +++ b/tags/typescript.html @@ -1 +1 @@ -typescript - John's Codes

    Typescript

    \ No newline at end of file +typescript - John's Codes

    Typescript

    \ No newline at end of file