<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Coding Talkies]]></title><description><![CDATA[Developer-focused blog offering practical tutorials, tips, and insights on JavaScript, TypeScript, Node.js, and web development to help you level up your coding skills and stay updated]]></description><link>https://codingtalkies.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1754842890129/6570ca7b-5e69-4a13-b04b-4fb4987cce00.png</url><title>Coding Talkies</title><link>https://codingtalkies.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 08 Nov 2026 03:46:29 GMT</lastBuildDate><atom:link href="https://codingtalkies.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Master Mapped Types in TypeScript]]></title><description><![CDATA[Learn how to master mapped types in TypeScript to transform your types dynamically. Practical examples, tips, and pitfalls every dev should know.]]></description><link>https://codingtalkies.hashnode.dev/master-mapped-types-in-typescript</link><guid isPermaLink="true">https://codingtalkies.hashnode.dev/master-mapped-types-in-typescript</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[TypeScript Tutorial]]></category><category><![CDATA[TypeScript Generics]]></category><category><![CDATA[TypeSafety]]></category><category><![CDATA[tips and tricks]]></category><dc:creator><![CDATA[Potato Script]]></dc:creator><pubDate>Tue, 16 Sep 2025 12:00:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1756239731081/d9951048-b33b-4feb-b85b-5bde5c3d78e6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-tldr">TL;DR</h3>
<p>Mapped types let you transform existing types into new shapes dynamically, without repeating yourself. Mastering them unlocks flexible, DRY, and safer TypeScript code patterns you’ll use everywhere.</p>
<h2 id="heading-why-mapped-types-deserve-your-attention">Why Mapped Types Deserve Your Attention</h2>
<p>When I first stumbled on mapped types, it felt like magic. I had been writing the same verbose type definitions again and again, until I realized TypeScript could do the work for me.</p>
<p>Mapped types let you take an existing type and transform it systematically, changing its keys, altering its modifiers, or reshaping it entirely. Think of it like SQL for types: you query, project, and reshape, but at the type level.</p>
<p>And the best part? Your editor will thank you with autocomplete and type safety for free.</p>
<h2 id="heading-the-basics-what-are-mapped-types">The Basics: What Are Mapped Types?</h2>
<p>Mapped types let you create new types by iterating over the keys of another type. You’ll usually see them paired with <code>keyof</code> and conditional types.</p>
<p>Here’s the canonical example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Readonly&lt;T&gt; = {
  <span class="hljs-keyword">readonly</span> [K <span class="hljs-keyword">in</span> keyof T]: T[K];
}

<span class="hljs-keyword">type</span> User = {
  id: <span class="hljs-built_in">number</span>;
  name: <span class="hljs-built_in">string</span>;
  active: <span class="hljs-built_in">boolean</span>;
}

<span class="hljs-keyword">type</span> ReadonlyUser = Readonly&lt;User&gt;;

<span class="hljs-keyword">const</span> user: ReadonlyUser = {
  id: <span class="hljs-number">1</span>,
  name: <span class="hljs-string">"John"</span>,
  active: <span class="hljs-literal">true</span>
};

user.active = <span class="hljs-literal">false</span>; <span class="hljs-comment">// Error: Cannot assign to 'active' because it is a read-only property.</span>
</code></pre>
<p>We “mapped” over each property of <code>User</code>, added <code>readonly</code>, and produced a new type. That’s the power of mapped types in action.</p>
<h2 id="heading-transforming-properties-dynamically">Transforming Properties Dynamically</h2>
<p>You don’t have to stop at adding <code>readonly</code>. You can dynamically transform keys, values, or modifiers.</p>
<h3 id="heading-example-1-making-all-fields-optional">Example 1: Making all fields optional</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Partial&lt;T&gt; = {
  [K <span class="hljs-keyword">in</span> keyof T]?: T[K];
};

<span class="hljs-keyword">type</span> Config = {
  host: <span class="hljs-built_in">string</span>;
  port: <span class="hljs-built_in">number</span>;
}

<span class="hljs-keyword">type</span> PartialConfig = Partial&lt;Config&gt;;
<span class="hljs-comment">/*
{
  host?: string | undefined;
  port?: number | undefined;
}
*/</span>
</code></pre>
<p>This is essentially how TypeScript’s built-in <code>Partial&lt;T&gt;</code> works.</p>
<h3 id="heading-example-2-changing-value-types">Example 2: Changing Value Types</h3>
<p>What if you want all values to become <code>string</code>?</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Stringify&lt;T&gt; = {
  [K <span class="hljs-keyword">in</span> keyof T]: <span class="hljs-built_in">string</span>;
};

<span class="hljs-keyword">type</span> EnvVars = {
  NODE_ENV: <span class="hljs-string">"production"</span> | <span class="hljs-string">"development"</span>;
  PORT: <span class="hljs-built_in">number</span>;
};

<span class="hljs-keyword">type</span> StringifiedEnv = Stringify&lt;EnvVars&gt;;
<span class="hljs-comment">/*
{
  NODE_ENV: string;
  PORT: string;
}
*/</span>
</code></pre>
<p>This is surprisingly useful for things like environment configs, where the actual runtime values are strings.</p>
<h3 id="heading-example-3-key-remapping-with-as">Example 3: Key Remapping with <code>as</code></h3>
<p>One of the newer TypeScript features is key remapping inside mapped types. This lets you rename keys dynamically.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> PrefixKeys&lt;T, P <span class="hljs-keyword">extends</span> <span class="hljs-built_in">string</span>&gt; = {
  [K <span class="hljs-keyword">in</span> keyof T <span class="hljs-keyword">as</span> <span class="hljs-string">`<span class="hljs-subst">${P}</span><span class="hljs-subst">${Capitalize&lt;<span class="hljs-built_in">string</span> &amp; K&gt;}</span>`</span>]: T[K]
}

<span class="hljs-keyword">type</span> Options = {
  dark: <span class="hljs-built_in">boolean</span>;
  compact: <span class="hljs-built_in">boolean</span>;
}

<span class="hljs-keyword">type</span> PrefixedOptions = PrefixKeys&lt;Options, <span class="hljs-string">"is"</span>&gt;;

<span class="hljs-comment">/*
{
  isDark: boolean;
  isCompact: boolean;
}
*/</span>
</code></pre>
<p>That’s some real power: not only mapping but also reshaping the keys themselves.</p>
<h2 id="heading-practical-use-cases">Practical Use Cases</h2>
<h3 id="heading-1-api-response-normalization">1. API Response Normalization</h3>
<p>If you’re consuming APIs where all fields are snake_case, but you want camelCase in your app:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> SnakeToCamel&lt;T&gt; = {
  [K <span class="hljs-keyword">in</span> keyof T <span class="hljs-keyword">as</span> K <span class="hljs-keyword">extends</span> <span class="hljs-string">`<span class="hljs-subst">${infer F}</span>_<span class="hljs-subst">${infer R}</span>`</span> ? <span class="hljs-string">`<span class="hljs-subst">${F}</span><span class="hljs-subst">${Capitalize&lt;R&gt;}</span>`</span>
  : K]: T[K];
}

<span class="hljs-keyword">type</span> ApiUser = {
  first_name: <span class="hljs-built_in">string</span>;
  last_name: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">type</span> User = SnakeToCamel&lt;ApiUser&gt;;
<span class="hljs-comment">/*
{
  firstName: string;
  lastName: string;
}
*/</span>
</code></pre>
<h3 id="heading-2-role-based-access-control">2. Role-Based Access Control</h3>
<p>You can generate permissions from a role definition automatically:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Actions&lt;T&gt; = {
  [K <span class="hljs-keyword">in</span> keyof T <span class="hljs-keyword">as</span> <span class="hljs-string">`can<span class="hljs-subst">${Capitalize&lt;<span class="hljs-built_in">string</span> &amp; K&gt;}</span>`</span>]: <span class="hljs-built_in">boolean</span>;
}

<span class="hljs-keyword">type</span> Features = {
  edit: {};
  <span class="hljs-keyword">delete</span>: {};
  view: {};
};

<span class="hljs-keyword">type</span> Permissions = Actions&lt;Features&gt;;
<span class="hljs-comment">/*
{
  canEdit: boolean;
  canDelete: boolean;
  canView: boolean;
}
*/</span>
</code></pre>
<h3 id="heading-3-enforcing-client-side-forms">3. Enforcing Client-Side Forms</h3>
<p>Transform backend types into “form-ready” types where everything becomes optional and string-based:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Formify&lt;T&gt; = {
  [K <span class="hljs-keyword">in</span> keyof T]?: <span class="hljs-built_in">string</span>;
};

<span class="hljs-keyword">type</span> Product = {
  id: <span class="hljs-built_in">number</span>;
  name: <span class="hljs-built_in">string</span>;
  price: <span class="hljs-built_in">number</span>;
};

<span class="hljs-keyword">type</span> ProductForm = Formify&lt;Product&gt;;
<span class="hljs-comment">/*
{
  id?: string;
  name?: string;
  price?: string;
}
*/</span>
</code></pre>
<h2 id="heading-gotchas-amp-tips">Gotchas &amp; Tips</h2>
<ul>
<li><p><strong>Watch out for unions:</strong> Mapped types over union keys can sometimes produce unexpected distributive behavior. Wrap with <code>keyof T &amp; string</code> to keep things tidy.</p>
</li>
<li><p><strong>Don’t overcomplicate</strong>: It’s tempting to go wild with conditional and template literal types. Keep it readable.</p>
</li>
<li><p><strong>Modifiers stack</strong>: You can combine <code>readonly</code> and <code>?</code> in the same mapped type. Useful, but don’t create awkward types.</p>
</li>
<li><p><strong>Runtime mismatch</strong>: Remember mapped types only exist at compile time. You still need runtime validation (e.g., <code>zod</code>) if dealing with untrusted data.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Mapped types are a powerful way to simplify and streamline your TypeScript code. Start by refactoring verbose type definitions, study how built-in utility types like <code>Partial</code>, <code>Required</code>, <code>Pick</code>, and <code>Record</code> are implemented, and then gradually explore advanced patterns using template literal and conditional types. Mastering these concepts will help you write cleaner, more flexible, and maintainable type definitions.</p>
<hr />
<p>Enjoyed this article? Give it a <strong>share</strong> and help someone else level up their coding skills!</p>
<p>Don’t stop here, <strong>explore</strong> my other TypeScript and developer-focused articles, and <strong>follow me</strong> for more.</p>
<p><a target="_blank" href="https://www.youtube.com/@potatoscript">▶️Youtube channel</a> | <a target="_blank" href="http://moucodes.redbubble.com/">👕Check out my store</a></p>
]]></content:encoded></item><item><title><![CDATA[Automate Type Extraction in TypeScript with ReturnType and Parameters]]></title><description><![CDATA[Learn how to use TypeScript's ReturnType and Parameters to automate type extraction, reduce boilerplate, and write safer and cleaner code]]></description><link>https://codingtalkies.hashnode.dev/automate-type-extraction-in-typescript-with-returntype-and-parameters</link><guid isPermaLink="true">https://codingtalkies.hashnode.dev/automate-type-extraction-in-typescript-with-returntype-and-parameters</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[TypeScript Tutorial]]></category><category><![CDATA[TypeScript Generics]]></category><category><![CDATA[TypeSafety]]></category><category><![CDATA[tips and tricks]]></category><dc:creator><![CDATA[Potato Script]]></dc:creator><pubDate>Thu, 11 Sep 2025 12:00:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1756249718990/7ebbe06b-1253-46f8-acbb-904b061a23dc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-tldr">TL;DR</h3>
<p>TypeScript’s built-in utility types <code>ReturnType</code> and <code>Parameters</code> can save you from repeating yourself by automatically inferring function signatures. They make your code safer, more maintainable, and more fun to write.</p>
<h2 id="heading-why-this-matters">Why This Matters</h2>
<p>One of the biggest joys of TypeScript is its ability to infer. The less we write explicit types, the less we risk introducing human error. And yet, I still see developers manually writing out argument and return types for functions all over their codebase, sometimes duplicating the same type definitions in multiple places.</p>
<p>If you’ve been there, you know how painful it is when you refactor a function and suddenly half your code breaks because you forgot to update the duplicated types.</p>
<p>That’s where <code>ReturnType</code> and <code>Parameters</code> shine. These utility types let you extract type information directly from your functions, keeping your code <strong>DRY</strong> and resilient to change.</p>
<h2 id="heading-meet-the-typescript-utility-types">Meet the TypeScript Utility Types</h2>
<h3 id="heading-returntype"><code>ReturnType&lt;T&gt;</code></h3>
<p>Extracts the return type of a given function type.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchUser</span>(<span class="hljs-params">id: <span class="hljs-built_in">string</span></span>) </span>{
  <span class="hljs-keyword">return</span> { id, name: <span class="hljs-string">"Alice"</span>, age: <span class="hljs-number">25</span> };
}

<span class="hljs-keyword">type</span> User = ReturnType&lt;<span class="hljs-keyword">typeof</span> fetchUser&gt;;
<span class="hljs-comment">/*
type User = { 
  id: string;
  name: string;
  age: number
}
*/</span>
</code></pre>
<p>With just one line, you’ve eliminated the need to manually define <code>User</code>. If you ever change <code>fetchUser</code> to include a new field, the type updates automatically.</p>
<h3 id="heading-parameters"><code>Parameters&lt;T&gt;</code></h3>
<p>Extracts the parameter types of a given function type as a tuple.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendMessage</span>(<span class="hljs-params">to: <span class="hljs-built_in">string</span>, message: <span class="hljs-built_in">string</span>, urgent?: <span class="hljs-built_in">boolean</span></span>) </span>{
  <span class="hljs-keyword">return</span> { to, message, urgent: !!urgent };
}

<span class="hljs-keyword">type</span> SendMessageArgs = Parameters&lt;<span class="hljs-keyword">typeof</span> sendMessage&gt;;
<span class="hljs-comment">// type SendMessageArgs = [to: string, message: string, urgent?: boolean | undefined]</span>

<span class="hljs-keyword">const</span> args: SendMessageArgs = [<span class="hljs-string">"bob@example.com"</span>, <span class="hljs-string">"Hello!"</span>, <span class="hljs-literal">true</span>];
sendMessage(...args);
</code></pre>
<h2 id="heading-why-bother">Why Bother?</h2>
<p>Let me share a quick story. A while back, I was working on a Node.js service with dozens of API handlers. Each handler had a corresponding type definition file. We’d often refactor handlers, changing parameters or response shapes. Every time, someone would forget to update the types in the <code>.d.ts</code> file, which caused runtime bugs slipping past review.</p>
<p>Once we switched to inferring types with <code>ReturnType</code> and <code>Parameters</code>, those errors disappeared. And as a bonus, our codebase suddenly felt lighter and more consistent.</p>
<h2 id="heading-real-world-patterns">Real-World Patterns</h2>
<h3 id="heading-reusing-parameters-in-higher-order-functions">Reusing Parameters in Higher-Order Functions</h3>
<p>Sometimes you wrap functions for logging, caching, or error handling. Instead of redefining the parameter types:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withLogging</span>&lt;<span class="hljs-title">T</span> <span class="hljs-title">extends</span> (<span class="hljs-params">...args: <span class="hljs-built_in">any</span>[]</span>) =&gt; <span class="hljs-title">any</span>&gt;(<span class="hljs-params">fn: T</span>) </span>{
  <span class="hljs-keyword">return</span> (...args: Parameters&lt;T&gt;): ReturnType&lt;T&gt; =&gt; {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Calling with args:"</span>, args);
    <span class="hljs-keyword">return</span> fn(...args);
  };
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sum</span>(<span class="hljs-params">a: <span class="hljs-built_in">number</span>, b: <span class="hljs-built_in">number</span></span>) </span>{
  <span class="hljs-keyword">return</span> a + b;
}

<span class="hljs-keyword">const</span> loggedSum = withLogging(sum);
<span class="hljs-keyword">const</span> result = loggedSum(<span class="hljs-number">3</span>, <span class="hljs-number">4</span>);

<span class="hljs-built_in">console</span>.log(result);
<span class="hljs-comment">/*
Calling with args: [ 3, 4 ]
result =&gt; 7
*/</span>
</code></pre>
<h3 id="heading-event-handlers">Event Handlers</h3>
<p>In React or Node.js apps, you often need to wire up handlers. Extracting parameter types makes handlers more predictable:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onUserLogin</span>(<span class="hljs-params">userId: <span class="hljs-built_in">string</span>, timestamp: <span class="hljs-built_in">Date</span></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"User logged in:"</span>, userId, timestamp);
}

<span class="hljs-keyword">type</span> LoginHandler = <span class="hljs-function">(<span class="hljs-params">...args: Parameters&lt;<span class="hljs-keyword">typeof</span> onUserLogin&gt;</span>) =&gt;</span> <span class="hljs-built_in">void</span>;

<span class="hljs-keyword">const</span> handler: LoginHandler = <span class="hljs-function">(<span class="hljs-params">id, date</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Handling login"</span>, id, date);
};
</code></pre>
<h2 id="heading-gotchas-amp-tips">Gotchas &amp; Tips</h2>
<ul>
<li><p><code>ReturnType</code> with async functions → Wrap with <code>Awaited&lt;T&gt;</code> to get the resolved value instead of the <code>Promise</code>.</p>
</li>
<li><p><strong>Overloaded functions</strong> → Only the last overload is used by <code>ReturnType</code> or <code>Parameters</code>. Be cautious if you rely heavily on overloads.</p>
</li>
<li><p><strong>Third-party APIs</strong> → Works best when functions are typed correctly. If the library uses <code>any</code>, utility types won’t save you.</p>
</li>
<li><p><strong>Avoid misuse</strong> → Don’t use these utilities everywhere “just because.” They shine in shared, reusable, or frequently refactored code.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>TypeScript’s <code>ReturnType</code> and <code>Parameters</code> keep your code DRY, safe, and easy to refactor by inferring types directly from functions. Use them to reduce duplication, prevent errors, and keep your codebase clean and future-proof.</p>
<hr />
<p>Enjoyed this article? Give it a <strong>share</strong> and help someone else level up their coding skills!</p>
<p>Don’t stop here, <strong>explore</strong> my other TypeScript and developer-focused articles, and <strong>follow me</strong> for more.</p>
<p><a target="_blank" href="https://www.youtube.com/@potatoscript">▶️Youtube channel</a> | <a target="_blank" href="http://moucodes.redbubble.com/">👕Check out my store</a></p>
]]></content:encoded></item><item><title><![CDATA[Create Recursive Types for Deeply Nested Data Structures in TypeScript]]></title><description><![CDATA[Learn how to create recursive types in TypeScript to model deeply nested data structures like trees, JSON, or configs,without breaking type safety]]></description><link>https://codingtalkies.hashnode.dev/create-recursive-types-for-deeply-nested-data-structures-in-typescript</link><guid isPermaLink="true">https://codingtalkies.hashnode.dev/create-recursive-types-for-deeply-nested-data-structures-in-typescript</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[TypeSafety]]></category><category><![CDATA[tips and tricks]]></category><category><![CDATA[Learn TypeScript]]></category><category><![CDATA[TypeScript Tutorial]]></category><dc:creator><![CDATA[Potato Script]]></dc:creator><pubDate>Tue, 09 Sep 2025 12:00:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1756249990536/aaef54c9-b98f-463e-a322-6e766894e993.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-tldr">TL;DR</h3>
<p>Recursive types let you model arbitrarily nested objects, arrays, and trees in TypeScript with strong type safety. This article shows you how to design them cleanly while avoiding common pitfalls.</p>
<h2 id="heading-why-recursive-types-matter">Why Recursive Types Matter</h2>
<p>If you’ve ever tried modeling a deeply nested JSON object, a tree-like category structure, or even a configuration file in TypeScript, you’ve probably hit a wall. At first, you think:</p>
<blockquote>
<p>"Okay, I’ll just define an interface, add a children field, done."</p>
</blockquote>
<p>But then requirements creep in, your data could be arbitrarily nested, arrays inside objects inside arrays, and suddenly your static types can’t keep up.</p>
<p>Recursive types are the answer. With them, you can build <strong>self-referential types</strong> that describe data structures of any depth, all while keeping TypeScript happy.</p>
<p>When I first stumbled on this problem, I was modeling categories for an e-commerce integration. Some categories had children, some didn’t, and some children had children. Without recursive types, my code turned into spaghetti. Recursive types saved me.</p>
<h2 id="heading-a-gentle-intro-recursive-types-101">A Gentle Intro: Recursive Types 101</h2>
<p>Let’s start small. Imagine we want to type a comment thread, each comment can have replies, and those replies are themselves comments.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Comment = {
  id: <span class="hljs-built_in">string</span>;
  text: <span class="hljs-built_in">string</span>;
  replies?: Comment[]; <span class="hljs-comment">// recursive reference</span>
};
</code></pre>
<p>This is the simplest form of recursion: a type that <strong>refers to itself</strong>.</p>
<ul>
<li><p><code>Comment</code> has a <code>replies</code> field.</p>
</li>
<li><p><code>replies</code> is an array of <code>Comment</code>.</p>
</li>
<li><p>Now have an infinitely nestable structure.</p>
</li>
</ul>
<h2 id="heading-deeply-nested-objects-json-like-structures">Deeply Nested Objects (JSON-like Structures)</h2>
<p>Sometimes recursion isn’t about trees but <strong>arbitrarily nested key/value objects</strong>. A good example is JSON data.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> JSONValue =
  | <span class="hljs-built_in">string</span>
  | <span class="hljs-built_in">number</span>
  | <span class="hljs-built_in">boolean</span>
  | <span class="hljs-literal">null</span>
  | { [key: <span class="hljs-built_in">string</span>]: JSONValue }
  | JSONValue[];

<span class="hljs-keyword">const</span> config: JSONValue = {
  database: {
    host: <span class="hljs-string">"localhost"</span>,
    ports: [<span class="hljs-number">5432</span>, <span class="hljs-number">5433</span>],
    ssl: <span class="hljs-literal">false</span>,
  },
  features: {
    darkMode: <span class="hljs-literal">true</span>,
    languages: [<span class="hljs-string">"en"</span>, <span class="hljs-string">"fr"</span>, <span class="hljs-string">"jp"</span>],
  },
};
</code></pre>
<p>Now, TypeScript knows that <code>JSONValue</code> can be any depth of objects or arrays.</p>
<h2 id="heading-utility-types-for-deep-nesting">Utility Types for Deep Nesting</h2>
<p>Sometimes you don’t just want to define data, you want utilities that <strong>work recursively</strong>. A classic example is a <code>DeepPartial</code>, which makes every field optional at every depth.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> DeepPartial&lt;T&gt; = {
  [K <span class="hljs-keyword">in</span> keyof T]?: T[K] <span class="hljs-keyword">extends</span> <span class="hljs-built_in">object</span>
  ? DeepPartial&lt;T[K]&gt;
  : T[K];
};

<span class="hljs-keyword">interface</span> UserProfile {
  id: <span class="hljs-built_in">string</span>;
  info: {
    name: <span class="hljs-built_in">string</span>;
    address: {
      city: <span class="hljs-built_in">string</span>;
      postalCode: <span class="hljs-built_in">string</span>;
    };
  };
}

<span class="hljs-keyword">type</span> PartialProfile = DeepPartial&lt;UserProfile&gt;;

<span class="hljs-keyword">const</span> update: PartialProfile = {
  info: {
    address: {
      city: <span class="hljs-string">"New York"</span>,
    },
  },
};
</code></pre>
<p>Without recursive typing, you’d have to manually define partials for each nested level. That’s not scalable.</p>
<h2 id="heading-gotchas-and-tips">Gotchas and Tips</h2>
<p>Recursive types are powerful, but they can bite you if you’re not careful.</p>
<ul>
<li><p><strong>Too Deep Recursion = Compiler Sadness</strong></p>
<p>  TypeScript has a recursion depth limit (~1000). If your type goes crazy, the compiler will complain.</p>
</li>
<li><p><strong>Don’t Over-Engineer</strong></p>
<p>  If you only ever nest 1–2 levels, a simple union might be easier to read than a recursive type.</p>
</li>
<li><p><strong>Watch Out for</strong> <code>any</code> Leaks</p>
<p>  Recursive utilities (like <code>DeepPartial</code>) often need conditional types. If you forget the base case, TypeScript falls back to <code>any</code>.</p>
</li>
<li><p><strong>Performance</strong></p>
<p>  Complex recursive types can slow IntelliSense and type-checking in large projects. Use them wisely.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Recursive types aren’t something you’ll use every day, but they’re incredibly powerful when working with deeply nested data like JSON, configs, or complex domain models. They provide strong type safety and confidence in your code. To level up, try creating your own utilities, modeling real-world data, and exploring advanced conditional types in the TypeScript docs to push your understanding even further.</p>
<hr />
<p>Enjoyed this article? Give it a <strong>share</strong> and help someone else level up their coding skills!</p>
<p>Don’t stop here, <strong>explore</strong> my other TypeScript and developer-focused articles, and <strong>follow me</strong> for more.</p>
<p><a target="_blank" href="https://www.youtube.com/@potatoscript">▶️Youtube channel</a> | <a target="_blank" href="http://moucodes.redbubble.com/">👕Check out my store</a></p>
]]></content:encoded></item><item><title><![CDATA[Mastering keyof and Lookup Types in TypeScript]]></title><description><![CDATA[Learn how to use keyof and lookup types in TypeScript for dynamic property access, safer utilities, and flexible APIs—without sacrificing type safety.]]></description><link>https://codingtalkies.hashnode.dev/mastering-keyof-and-lookup-types-in-typescript</link><guid isPermaLink="true">https://codingtalkies.hashnode.dev/mastering-keyof-and-lookup-types-in-typescript</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[Types]]></category><category><![CDATA[TypeScript Tutorial]]></category><category><![CDATA[keyof]]></category><category><![CDATA[tips and tricks]]></category><dc:creator><![CDATA[Potato Script]]></dc:creator><pubDate>Fri, 05 Sep 2025 12:00:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1756250313946/b7c027a9-93ce-483f-b85b-6e764d15a1af.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-tldr">TL;DR</h2>
<p>TypeScript’s <code>keyof</code> and lookup types let you access object properties dynamically with full type safety. They make your code flexible without falling back to <code>any</code>.</p>
<h2 id="heading-why-should-you-care-about-keyof-and-lookup-types">Why Should You Care About <code>keyof</code> and Lookup Types?</h2>
<p>At some point, every TypeScript developer faces this:</p>
<ul>
<li><p>You want to write a function that takes an object and a property name.</p>
</li>
<li><p>You want that property name to be type-checked.</p>
</li>
<li><p>You want the return value to be correctly typed based on the property.</p>
</li>
</ul>
<p>If you use <code>any</code> or plain strings, you lose type safety. If you try to hardcode every case, your function becomes rigid and unscalable.</p>
<p>Enter <code>keyof</code> and <strong>lookup types</strong>. These two features unlock the ability to <strong>dynamically access properties while keeping everything type-safe</strong>.</p>
<h2 id="heading-keyof-in-action"><code>keyof</code> in Action</h2>
<p>The <code>keyof</code> operator takes an object type and produces a union of its keys.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> User {
  id: <span class="hljs-built_in">number</span>;
  name: <span class="hljs-built_in">string</span>;
  email: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">type</span> UserKeys = keyof User;
<span class="hljs-comment">// "id" | "name" | "email"</span>
</code></pre>
<p>Now, <code>UserKeys</code> is a type representing all valid keys of <code>User</code>.</p>
<p>That means you can write functions like this:</p>
<pre><code class="lang-typescript">unction getProperty(obj: User, key: keyof User) {
  <span class="hljs-keyword">return</span> obj[key];
}

<span class="hljs-keyword">const</span> user: User = { id: <span class="hljs-number">1</span>, name: <span class="hljs-string">"John"</span>, email: <span class="hljs-string">"john@example.com"</span> };

<span class="hljs-keyword">const</span> name = getProperty(user, <span class="hljs-string">"name"</span>);
<span class="hljs-keyword">const</span> id = getProperty(user, <span class="hljs-string">"id"</span>);
<span class="hljs-keyword">const</span> age = getProperty(user, <span class="hljs-string">"age"</span>);
<span class="hljs-comment">// Error: Argument of type '"age"' is not assignable to parameter of type 'keyof User'</span>
</code></pre>
<h2 id="heading-lookup-types-tk">Lookup Types (<code>T[K]</code>)</h2>
<p>Lookup types let you get the <strong>type of a property by its key</strong>. Think of them as “indexing” into a type.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> UserName = User[<span class="hljs-string">"name"</span>]; <span class="hljs-comment">// string</span>
<span class="hljs-keyword">type</span> UserId = User[<span class="hljs-string">"id"</span>];     <span class="hljs-comment">// number</span>
</code></pre>
<p>This is insanely useful when combined with generics.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getProperty</span>&lt;<span class="hljs-title">T</span>, <span class="hljs-title">K</span> <span class="hljs-title">extends</span> <span class="hljs-title">keyof</span> <span class="hljs-title">T</span>&gt;(<span class="hljs-params">obj: T, key: K</span>): <span class="hljs-title">T</span>[<span class="hljs-title">K</span>] </span>{
  <span class="hljs-keyword">return</span> obj[key];
}

<span class="hljs-keyword">const</span> email = getProperty(user, <span class="hljs-string">"email"</span>);
</code></pre>
<p>Without lookup types, you’d just get <code>string | number | ...</code>. With them, you get <strong>exactly the right type</strong>.</p>
<h2 id="heading-building-safer-utilities-with-keyof-lookup-types">Building Safer Utilities with <code>keyof</code> + Lookup Types</h2>
<h3 id="heading-example-1-filtering-an-array-by-a-property">Example 1: Filtering an Array by a Property</h3>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">filterBy</span>&lt;<span class="hljs-title">T</span>, <span class="hljs-title">K</span> <span class="hljs-title">extends</span> <span class="hljs-title">keyof</span> <span class="hljs-title">T</span>&gt;(<span class="hljs-params">
  arr: T[],
  key: K,
  value: T[K]
</span>): <span class="hljs-title">T</span>[] </span>{
  <span class="hljs-keyword">return</span> arr.filter(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> item[key] === value);
}

<span class="hljs-keyword">const</span> users: User[] = [
  { id: <span class="hljs-number">1</span>, name: <span class="hljs-string">"John"</span>, email: <span class="hljs-string">"john@example.com"</span> },
  { id: <span class="hljs-number">2</span>, name: <span class="hljs-string">"Alice"</span>, email: <span class="hljs-string">"alice@example.com"</span> },
];

<span class="hljs-keyword">const</span> result = filterBy(users, <span class="hljs-string">"name"</span>, <span class="hljs-string">"Alice"</span>);
<span class="hljs-comment">// result is User[]</span>
</code></pre>
<p>Notice how <code>value</code> is typed as <code>T[K]</code>. If you try to pass a number when the property expects a string, TypeScript blocks you.</p>
<h3 id="heading-example-2-picking-multiple-properties">Example 2: Picking Multiple Properties</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> user: User = { id: <span class="hljs-number">1</span>, name: <span class="hljs-string">"John"</span>, email: <span class="hljs-string">"john@example.com"</span> };

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">pick</span>&lt;<span class="hljs-title">T</span>, <span class="hljs-title">K</span> <span class="hljs-title">extends</span> <span class="hljs-title">keyof</span> <span class="hljs-title">T</span>&gt;(<span class="hljs-params">obj: T, keys: K[]</span>): <span class="hljs-title">Pick</span>&lt;<span class="hljs-title">T</span>, <span class="hljs-title">K</span>&gt; </span>{
  <span class="hljs-keyword">const</span> result = {} <span class="hljs-keyword">as</span> Pick&lt;T, K&gt;;
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> key <span class="hljs-keyword">of</span> keys) {
    result[key] = obj[key];
  }
  <span class="hljs-keyword">return</span> result;
}

<span class="hljs-keyword">const</span> picked = pick(user, [<span class="hljs-string">"id"</span>, <span class="hljs-string">"email"</span>]);
<span class="hljs-comment">// { id: number; email: string }</span>
<span class="hljs-built_in">console</span>.log(picked);
<span class="hljs-comment">// {name: "John", email: "john@example.com"}</span>
</code></pre>
<h3 id="heading-example-3-enforcing-valid-keys-in-configs">Example 3: Enforcing Valid Keys in Configs</h3>
<p>Imagine you’re building a logger that only allows certain config keys.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> LoggerConfig {
  level: <span class="hljs-string">"info"</span> | <span class="hljs-string">"warn"</span> | <span class="hljs-string">"error"</span>;
  output: <span class="hljs-string">"console"</span> | <span class="hljs-string">"file"</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setConfig</span>&lt;<span class="hljs-title">K</span> <span class="hljs-title">extends</span> <span class="hljs-title">keyof</span> <span class="hljs-title">LoggerConfig</span>&gt;(<span class="hljs-params">
  key: K,
  value: LoggerConfig[K]
</span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Setting <span class="hljs-subst">${key}</span> to <span class="hljs-subst">${value}</span>`</span>);
}

setConfig(<span class="hljs-string">"level"</span>, <span class="hljs-string">"warn"</span>);   <span class="hljs-comment">// ✅ valid</span>
setConfig(<span class="hljs-string">"output"</span>, <span class="hljs-string">"file"</span>);  <span class="hljs-comment">// ✅ valid</span>
setConfig(<span class="hljs-string">"output"</span>, <span class="hljs-string">"db"</span>);    <span class="hljs-comment">// ❌ error</span>
</code></pre>
<p>This ensures developers can’t accidentally pass unsupported config values.</p>
<h2 id="heading-gotchas-amp-tips">Gotchas &amp; Tips</h2>
<ul>
<li><p><strong>Watch for</strong> <code>string | number | symbol</code></p>
<p>  If you use <code>keyof</code> on something like <code>Record&lt;string, any&gt;</code>, you’ll get <code>string | number | symbol</code>, which can feel too broad. Narrow types where possible.</p>
</li>
<li><p><strong>Optional properties may return</strong> <code>undefined</code></p>
<p>  Lookup types don’t guarantee a property exists. If a key is optional, TypeScript includes <code>undefined</code> in the return type.</p>
</li>
<li><p><strong>Use constraints wisely</strong></p>
<p>  Always use <code>K extends keyof T</code> in generics. Without it, you lose type safety.</p>
</li>
<li><p><strong>Runtime vs Compile-Time</strong></p>
<p>  TypeScript only enforces keys at compile time. At runtime, invalid keys still break if unchecked. Consider runtime validation if inputs come from external sources.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p><code>keyof</code> and lookup types give you a foundation for building your own powerful utilities. With them, you can shape types to match your domain instead of forcing your code into generic patterns. The more you practice, the more you’ll find TypeScript’s type system isn’t just for safety, it’s a design tool that helps you think about your data more clearly.</p>
<hr />
<p>Enjoyed this article? Give it a <strong>share</strong> and help someone else level up their coding skills!</p>
<p>Don’t stop here, <strong>explore</strong> my other TypeScript and developer-focused articles, and <strong>follow me</strong> for more.</p>
<p><a target="_blank" href="https://www.youtube.com/@potatoscript">▶️Youtube channel</a> | <a target="_blank" href="http://moucodes.redbubble.com/">👕Check out my store</a></p>
]]></content:encoded></item><item><title><![CDATA[Unlock Template Literal Types for Type-Safe Strings in TypeScript]]></title><description><![CDATA[Learn how to use template literal types in TypeScript to enforce string patterns, create type-safe APIs, and reduce bugs,all while keeping code flexible.]]></description><link>https://codingtalkies.hashnode.dev/template-literal-types-in-typescript</link><guid isPermaLink="true">https://codingtalkies.hashnode.dev/template-literal-types-in-typescript</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[TypeSafety]]></category><category><![CDATA[TypeScript Tutorial]]></category><category><![CDATA[TypeScript tips]]></category><category><![CDATA[tips and tricks]]></category><dc:creator><![CDATA[Potato Script]]></dc:creator><pubDate>Tue, 02 Sep 2025 12:00:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1756250696578/1d08cab5-30e2-40a4-899a-f35609ab5043.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-tldr"><strong>TL;DR</strong></h3>
<p>Template literal types let you create type-safe string patterns in TypeScript. With them, you can enforce naming conventions, validate strings, and build smarter APIs, all at compile time.</p>
<h2 id="heading-why-template-literal-types-matter">Why Template Literal Types Matter</h2>
<p>Strings are everywhere in our applications: URLs, CSS class names, event names, IDs, keys. But here’s the problem: strings are often just…strings. To the compiler, <code>"user:created"</code> and <code>"users:create"</code> look the same.</p>
<p>That means typos slip through. Bugs hide. And you lose safety in some of the most critical parts of your app.</p>
<p>Enter <strong>template literal types</strong>. They let you <strong>define string patterns at the type level</strong>, giving TypeScript superpowers to check your strings <em>before</em> you even run your code.</p>
<p>When I first discovered template literal types, I used them to enforce consistent event names in a pub/sub system. Before that, I had mismatched topics between publisher and subscriber, and debugging was painful. Afterward, TypeScript caught mistakes immediately.</p>
<h2 id="heading-the-basics-template-literal-types">The Basics: Template Literal Types</h2>
<p>A template literal type is just like a string template literal in JavaScript, but at the type level.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> EventName = <span class="hljs-string">`user:<span class="hljs-subst">${<span class="hljs-string">"created"</span> | <span class="hljs-string">"deleted"</span> | <span class="hljs-string">"updated"</span>}</span>`</span>;

<span class="hljs-keyword">const</span> good: EventName = <span class="hljs-string">"user:created"</span>;  <span class="hljs-comment">// ✅ ok</span>
<span class="hljs-keyword">const</span> bad: EventName = <span class="hljs-string">"user:create"</span>;    <span class="hljs-comment">// ❌ error</span>
</code></pre>
<h2 id="heading-combining-with-keyof">Combining with <code>keyof</code></h2>
<p>Template literal types shine when combined with <code>keyof</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> API {
  getUser: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span>;
  createUser: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span>;
  deleteUser: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span>;
}

<span class="hljs-keyword">type</span> APIEvent = <span class="hljs-string">`<span class="hljs-subst">${keyof API}</span>Event`</span>;

<span class="hljs-keyword">const</span> e1: APIEvent = <span class="hljs-string">"getUserEvent"</span>;    <span class="hljs-comment">// ✅</span>
<span class="hljs-keyword">const</span> e2: APIEvent = <span class="hljs-string">"updateUserEvent"</span>; <span class="hljs-comment">// ❌ Error</span>
</code></pre>
<p>Now your event names automatically stay in sync with your API functions. If you add or remove a function, the compiler updates the valid events.</p>
<h2 id="heading-example-routing-with-type-safety">Example: Routing with Type Safety</h2>
<p>Imagine you’re building a router. You want route strings like <code>/users/:id</code> or <code>/posts/:id/comments</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Resource = <span class="hljs-string">"users"</span> | <span class="hljs-string">"posts"</span> | <span class="hljs-string">"comments"</span>;
<span class="hljs-keyword">type</span> Route = <span class="hljs-string">`/<span class="hljs-subst">${Resource}</span>/<span class="hljs-subst">${<span class="hljs-built_in">string</span>}</span>`</span>;

<span class="hljs-keyword">const</span> route1: Route = <span class="hljs-string">"/users/123"</span>;      <span class="hljs-comment">// ✅</span>
<span class="hljs-keyword">const</span> route2: Route = <span class="hljs-string">"/posts/456"</span>;      <span class="hljs-comment">// ✅</span>
<span class="hljs-keyword">const</span> route3: Route = <span class="hljs-string">"/accounts/789"</span>;   <span class="hljs-comment">// ❌ Error</span>
</code></pre>
<p>You can now guarantee that routes always start with a valid resource.</p>
<h2 id="heading-example-css-class-names">Example: CSS Class Names</h2>
<p>If you’re using utility-first CSS (like Tailwind), you can generate safe class name patterns.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Spacing = <span class="hljs-string">"1"</span> | <span class="hljs-string">"2"</span> | <span class="hljs-string">"3"</span> | <span class="hljs-string">"4"</span>;
<span class="hljs-keyword">type</span> Direction = <span class="hljs-string">"x"</span> | <span class="hljs-string">"y"</span> | <span class="hljs-string">"t"</span> | <span class="hljs-string">"b"</span>;

<span class="hljs-keyword">type</span> MarginClass = <span class="hljs-string">`m<span class="hljs-subst">${Direction}</span>-<span class="hljs-subst">${Spacing}</span>`</span>;

<span class="hljs-keyword">const</span> c1: MarginClass = <span class="hljs-string">"mx-2"</span>;   <span class="hljs-comment">// ✅</span>
<span class="hljs-keyword">const</span> c2: MarginClass = <span class="hljs-string">"mb-4"</span>;   <span class="hljs-comment">// ✅</span>
<span class="hljs-keyword">const</span> c3: MarginClass = <span class="hljs-string">"ml-3"</span>;   <span class="hljs-comment">// ❌ Error</span>
</code></pre>
<p>This ensures only valid spacing classes are allowed.</p>
<h2 id="heading-example-building-a-key-value-map-with-constraints">Example: Building a Key-Value Map with Constraints</h2>
<p>Template literal types are also great for modeling <strong>namespaced keys</strong> in config objects.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Env = <span class="hljs-string">"dev"</span> | <span class="hljs-string">"staging"</span> | <span class="hljs-string">"prod"</span>;
<span class="hljs-keyword">type</span> Service = <span class="hljs-string">"auth"</span> | <span class="hljs-string">"payments"</span> | <span class="hljs-string">"storage"</span>;

<span class="hljs-keyword">type</span> ConfigKey = <span class="hljs-string">`<span class="hljs-subst">${Env}</span>.<span class="hljs-subst">${Service}</span>.url`</span>;

<span class="hljs-keyword">const</span> key: ConfigKey = <span class="hljs-string">"prod.auth.url"</span>;    <span class="hljs-comment">// ✅</span>
<span class="hljs-keyword">const</span> badKey: ConfigKey = <span class="hljs-string">"local.auth.url"</span>; <span class="hljs-comment">// ❌ Error</span>
</code></pre>
<p>You’ve just given yourself compile-time safety for keys that otherwise would be unchecked strings.</p>
<h2 id="heading-gotchas-amp-tips">Gotchas &amp; Tips</h2>
<ul>
<li><p><strong>Literal Explosion</strong></p>
<p>  Be careful with unions that have many members. If you combine a union of 50 items with another 50, you could generate 2,500 types.</p>
</li>
<li><p><strong>Runtime vs Compile-Time</strong></p>
<p>  Template literal types don’t validate strings at runtime. They’re a compile-time check. For external inputs, you’ll still need runtime validation.</p>
</li>
<li><p><strong>String Interpolation</strong></p>
<p>  You can use <code>${string}</code> to allow flexibility, but this makes the type too broad. Use sparingly and only where necessary.</p>
</li>
<li><p><strong>IntelliSense Performance</strong></p>
<p>  Complex template literal types can slow down autocomplete. If you notice editor lag, simplify your unions.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Template literal types are a powerful way to enforce patterns directly in TypeScript. By combining them with <code>infer</code>, DSL-like constructs, and branded types, you can model complex conventions that were once only implicit. They don’t just improve type safety, they turn your compiler into an active enforcer of your design rules.</p>
<hr />
<p>Enjoyed this article? Give it a <strong>share</strong> and help someone else level up their coding skills!</p>
<p>Don’t stop here, <strong>explore</strong> my other TypeScript and developer-focused articles, and <strong>follow me</strong> for more.</p>
<p><a target="_blank" href="https://www.youtube.com/@potatoscript">▶️Youtube channel</a> | <a target="_blank" href="http://moucodes.redbubble.com/">👕Check out my store</a></p>
]]></content:encoded></item></channel></rss>