Advanced TypeScript Techniques: Conditional Types, Mapped Types, and Type Inference Strategies for Better Code

Published: (January 6, 2026 at 07:08 AM EST)
7 min read
Source: Dev.to

Source: Dev.to

As a best‑selling author, I invite you to explore my books on Amazon. Don’t forget to follow me on Medium and show your support. Thank you! Your support means the world!

TypeScript’s Type System – A Super‑Power

TypeScript’s type system often feels like a super‑power you can learn gradually. I started with simple annotations—string, number, basic interfaces—and over time discovered a whole other layer of techniques that let me describe the shape and behavior of my code with incredible precision. These methods catch mistakes before the code runs and make my editor feel intelligent. Below is a walk‑through of some of the most powerful methods, from foundational to advanced.

1. Conditional Types

Think of them as “if statements” for your types. They let a type decide what it is based on another type, which is useful for creating flexible utilities.

type IsNumber<T> = T extends number ? true : false;

type TestA = IsNumber<string>; // false
type TestB = IsNumber<42>;    // true

infer inside a conditional type

Capture a piece of another type. A classic example is extracting the return type of a function you don’t yet know.

type WhatDoesThisReturn<T> =
  T extends (...args: any) => infer ReturnType ? ReturnType : never;

function fetchData() {
  return { id: 1, title: 'Item' };
}

type FetchedData = WhatDoesThisReturn<typeof fetchData>;
// FetchedData is now { id: number; title: string; }

Distribution over unions

Conditional types automatically distribute over union members.

type ToArray<T> = T extends any ? T[] : never;
type Result = ToArray<string | number>; // string[] | number[]

Preventing distribution

Wrap the check in a tuple to stop distribution.

type ToArrayNoDistribute<T> = [T] extends [any] ? T[] : never;
type Result2 = ToArrayNoDistribute<string | number>; // (string | number)[]

2. Mapped Types

Create a new type by transforming each property of an existing type—similar to Array.map() but for object keys.

Basic mapped types

type MakeAllOptional<T> = {
  [Key in keyof T]?: T[Key];
};

type MakeAllReadonly<T> = {
  readonly [Key in keyof T]: T[Key];
};

interface User {
  id: number;
  name: string;
}

type PartialUser = MakeAllOptional<User>;
// { id?: number; name?: string; }

type ReadonlyUser = MakeAllReadonly<User>;
// { readonly id: number; readonly name: string; }

Adding / removing modifiers

Use + or - to toggle ? (optional) or readonly.

type MakeRequired<T> = {
  [Key in keyof T]-?: T[Key];
};

type UserWithOptionalId = { id?: number; name: string };
type RequiredUser = MakeRequired<UserWithOptionalId>;
// { id: number; name: string; }

Key remapping with as

// Only keep properties that are functions
type FunctionProperties<T> = {
  [Key in keyof T as T[Key] extends Function ? Key : never]: T[Key];
};

// Add a 'get' prefix to every key
type Getters<T> = {
  [Key in keyof T as `get${Capitalize<string & Key>}`]: () => T[Key];
};

interface DataModel {
  value: number;
  calculate(): number;
}

type JustFunctions = FunctionProperties<DataModel>; // { calculate: () => number; }
type DataGetters = Getters<DataModel>;
// { getValue: () => number; getCalculate: () => () => number; }

3. Template Literal Types

Manipulate string literal types using template‑string syntax. Great for type‑safe routes, CSS class names, or method names.

type Color = 'red' | 'blue';
type Size = 'sm' | 'lg';

type ButtonClass = `btn-${Size}-${Color}`;
// "btn-sm-red" | "btn-sm-blue" | "btn-lg-red" | "btn-lg-blue"

const myClass: ButtonClass = 'btn-lg-red'; // ✅ works
// const badClass: ButtonClass = 'btn-md-green'; // ❌ error

Parsing strings with infer

type ExtractParts<T> = T extends `btn-${infer S}-${infer C}` ? [S, C] : never;
type Parts = ExtractParts<'btn-sm-red'>; // ["sm", "red"]

4. Inference Operators

typeof – get the static type of a value

const config = { host: 'localhost', port: 3000 };
type Config = typeof config;
// { host: string; port: number; }

keyof – union of an object’s keys

interface Product {
  id: number;
  name: string;
  price: number;
}
type ProductKey = keyof Product; // "id" | "name" | "price"

Indexed access types – look up a property’s type

type ProductNameType = Product['name'];   // string
type ProductPriceType = Product['price']; // number

These techniques—conditional types, mapped types, template literal types, and inference operators—form a powerful toolbox that lets you write safer, more expressive TypeScript. Experiment with them, combine them, and watch your editor become a true coding ally. Happy typing!

Indexed Access Types, Utility Types, and Generics in TypeScript

Below are concise examples that demonstrate how to use indexed access types, utility types, generic constraints, and recursive types.

Indexed Access Types

interface Product {
  id: number;
  name: string;
  price: number;
}

// Get the type of a single property
type ProductId = Product['id']; // number

// Union of several properties
type IdOrName = Product['id' | 'name']; // number | string

Deep Indexed Access

interface APIResponse {
  data: {
    user: {
      id: string;
      profile: { name: string };
    };
  };
}

// Extract a deeply‑nested property type
type UserProfileName = APIResponse['data']['user']['profile']['name']; // string

Utility Types: Pick & Omit

interface FullUser {
  id: number;
  name: string;
  email: string;
  passwordHash: string;
  createdAt: Date;
}

/* Public‑facing data */
type PublicUser = Pick<FullUser, 'id' | 'name' | 'email'>;
/* { id: number; name: string; email: string; } */

/* Remove sensitive fields */
type SafeUser = Omit<FullUser, 'passwordHash'>;
/* { id: number; name: string; email: string; createdAt: Date; } */

How Pick Works (simplified)

// A minimal re‑implementation of Pick
type MyPick<T, K extends keyof T> = {
  [P in K]: T[P];
};

type PickedName = MyPick<FullUser, 'name' | 'email'>;
// { name: string; email: string; }

Constraining Generic Type Parameters

// Function that works only with objects that have an `id` property
function getById<T extends { id: string }>(items: T[], id: string): T | undefined {
  return items.find(item => item.id === id);
}

const users = [{ id: 'a1', name: 'Alice' }, { id: 'b2', name: 'Bob' }];
const found = getById(users, 'b2'); // { id: string; name: string; }

Constraining One Generic with Another

// Merge two objects; the result type is the intersection of both inputs
function merge<A, B>(a: A, b: B): A & B {
  return { ...a, ...b };
}

const result = merge({ foo: 1 }, { bar: 'two' });
// result: { foo: number; } & { bar: string; }

Recursive Types

Tree Structure

interface TreeNode<T> {
  value: T;
  children?: TreeNode<T>[];
}

const tree: TreeNode<string> = {
  value: 'root',
  children: [
    { value: 'child1' },
    { value: 'child2', children: [{ value: 'grandchild' }] }
  ]
};

Deeply Optional (DeepPartial)

type DeepPartial<T> = T extends object
  ? { [P in keyof T]?: DeepPartial<T[P]> }
  : T;

interface Settings {
  user: {
    theme: string;
    dashboard: { widgets: string[] };
  };
}

type PartialSettings = DeepPartial<Settings>;
/* All properties (user, theme, dashboard, widgets) become optional at any depth */

Takeaway

Use typeof and keyof to avoid repetition, then build small utility types with mapped or conditional types to solve specific problems (e.g., extracting all string properties from an interface). Over time these techniques become part of your regular workflow, turning the TypeScript compiler into a true partner that enforces contracts and reduces bugs.

📘 Checkout My Latest Ebook

Watch the free preview on YouTube

If you enjoy the content, please like, share, comment, and subscribe!

101 Books

101 Books is an AI‑driven publishing company co‑founded by author Aarav Joshi. By leveraging advanced AI technology, we keep publishing costs low—some titles are priced as low as $4—making quality knowledge accessible to everyone.

  • Golang Clean Code – available on Amazon
  • Search for Aarav Joshi to discover more titles and enjoy special discounts!

Our Creations

Explore our projects:

We Are on Medium

Tech Koala Insights – follow for more articles, tutorials, and deep dives into modern development topics.

Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Science & Epochs Medium | Modern Hindutva

Back to Blog

Related posts

Read more »

3 things I want to learn in 2026

n8n This has been covered a few times by Dev YouTubers and has piqued my interest. It's an open-source workflow automation tool that's fair‑code licensed, powe...

The Concise TypeScript Book

Article URL: https://github.com/gibbok/typescript-book Comments URL: https://news.ycombinator.com/item?id=46573001 Points: 4 Comments: 1...