Beyond the Basics: 10 TypeScript Features That Will Supercharge Your Code

TypeScript is more than just JavaScript with types—it’s a robust tool that helps you catch bugs early, scale confidently, and create more expressive APIs. While the basics like interfaces and type annotations are essential, mastering the advanced features unlocks serious power. In this post, we’ll dive into 10 advanced TypeScript concepts every modern developer should know, complete with examples, explanations, and real-world use cases. 1. Union Types Union types let a variable hold values of multiple possible types. let value: string | number; value = "Hello"; // OK value = 123; // OK function printStatus(status: "pending" | "approved" | "rejected") { console.log(`Status is: ${status}`); } printStatus("approved"); // Valid ✅ Use Case: API responses that can return different types (e.g., string or number). 2. Intersection Types Intersection types combine multiple types into one. The resulting type must satisfy all constituent types. interface Person { name: string; age: number; } interface Employee { employeeId: number; } type Developer = Person & Employee; const dev: Developer = { name: "Alice", age: 30, employeeId: 1001 }; ✅ Use Case: Combining shared types like User & Permissions or Props & Ref. 3. Type Guards Type guards help narrow down the type inside a conditional block. function isString(value: unknown): value is string { return typeof value === "string"; } function logValue(value: string | number) { if (isString(value)) { console.log(value.toUpperCase()); } else { console.log(value.toFixed(2)); } } ✅ Use Case: Safely handle union types or unknown types at runtime. 4. Conditional Types Conditional types enable logic within type declarations. type IsString = T extends string ? "Yes" : "No"; type A = IsString; // "Yes" type B = IsString; // "No" ✅ Use Case: Building type utilities like ReturnType, Exclude, etc. 5. Mapped Types Mapped types transform properties of existing types. type Readonly = { readonly [K in keyof T]: T[K]; }; type Nullable = { [K in keyof T]: T[K] | null; }; interface User { id: number; name: string; email: string; } const user: Readonly = { id: 1, name: "John", email: "john@example.com" }; // user.id = 2; // Error: Cannot assign to 'id' because it is a read-only property. type NullableUser = Nullable; ✅ Use Case: Creating variations of models, e.g., form inputs, API payloads. 6. Template Literal Types Build string-based types using interpolation. type Color = "red" | "green" | "blue"; type Mode = "light" | "dark"; type Theme = `${Mode}-${Color}`; const theme: Theme = "dark-red"; // OK // const invalid: Theme = "bright-yellow"; // Error ✅ Use Case: Define naming conventions, CSS class patterns, keys for theme systems. 7. Recursive Types Recursive types are useful for representing trees, menus, or nested structures. interface TreeNode { value: number; left?: TreeNode; right?: TreeNode; } const tree: TreeNode = { value: 1, left: { value: 2, left: { value: 3 }, right: { value: 4 } }, right: { value: 5 } }; ✅ Use Case: File systems, organizational charts, UI components like menus. 8. Keyof and Lookup Types Use keyof to get keys of a type, and lookup types to extract property types. interface User { id: number; name: string; } type UserKeys = keyof User; // "id" | "name" type IdType = User["id"]; // number 9. Infer Keyword infer is used in conditional types to extract and reuse inferred types. type ReturnType = T extends (...args: any[]) => infer R ? R : never; type Func = () => string; type Result = ReturnType; // string ✅ Use Case: Custom type helpers, like extracting result types of functions. 10. Utility Types TypeScript ships with powerful utility types: interface Task { id: number; title: string; completed?: boolean; } type PartialTask = Partial; // All properties optional type RequiredTask = Required; // All properties required type PickTitle = Pick; // Only 'title' type OmitId = Omit; // Exclude 'id' ✅ Use Case: Modify models without duplication, tailor types for APIs, forms, or components. Conclusion Advanced TypeScript features can help you build safer, scalable, and more expressive codebases. Whether you're working on frontend UI, backend APIs, or shared libraries, mastering these patterns will boost both confidence and productivity.

Apr 5, 2025 - 10:04
 0
Beyond the Basics: 10 TypeScript Features That Will Supercharge Your Code

TypeScript is more than just JavaScript with types—it’s a robust tool that helps you catch bugs early, scale confidently, and create more expressive APIs. While the basics like interfaces and type annotations are essential, mastering the advanced features unlocks serious power. In this post, we’ll dive into 10 advanced TypeScript concepts every modern developer should know, complete with examples, explanations, and real-world use cases.

1. Union Types

Union types let a variable hold values of multiple possible types.

let value: string | number;

value = "Hello";  // OK
value = 123;      // OK

function printStatus(status: "pending" | "approved" | "rejected") {
  console.log(`Status is: ${status}`);
}

printStatus("approved"); // Valid

✅ Use Case: API responses that can return different types (e.g., string or number).

2. Intersection Types

Intersection types combine multiple types into one. The resulting type must satisfy all constituent types.

interface Person {
  name: string;
  age: number;
}

interface Employee {
  employeeId: number;
}

type Developer = Person & Employee;

const dev: Developer = {
  name: "Alice",
  age: 30,
  employeeId: 1001
};

✅ Use Case: Combining shared types like User & Permissions or Props & Ref.

3. Type Guards

Type guards help narrow down the type inside a conditional block.

function isString(value: unknown): value is string {
  return typeof value === "string";
}

function logValue(value: string | number) {
  if (isString(value)) {
    console.log(value.toUpperCase());
  } else {
    console.log(value.toFixed(2));
  }
}

✅ Use Case: Safely handle union types or unknown types at runtime.

4. Conditional Types

Conditional types enable logic within type declarations.

type IsString = T extends string ? "Yes" : "No";

type A = IsString; // "Yes"
type B = IsString; // "No"

✅ Use Case: Building type utilities like ReturnType, Exclude, etc.

5. Mapped Types

Mapped types transform properties of existing types.

type Readonly = {
  readonly [K in keyof T]: T[K];
};

type Nullable = {
  [K in keyof T]: T[K] | null;
};

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

const user: Readonly = {
  id: 1,
  name: "John",
  email: "john@example.com"
};

// user.id = 2; // Error: Cannot assign to 'id' because it is a read-only property.

type NullableUser = Nullable;

✅ Use Case: Creating variations of models, e.g., form inputs, API payloads.

6. Template Literal Types

Build string-based types using interpolation.

type Color = "red" | "green" | "blue";
type Mode = "light" | "dark";

type Theme = `${Mode}-${Color}`;

const theme: Theme = "dark-red"; // OK
// const invalid: Theme = "bright-yellow"; // Error

✅ Use Case: Define naming conventions, CSS class patterns, keys for theme systems.

7. Recursive Types

Recursive types are useful for representing trees, menus, or nested structures.

interface TreeNode {
  value: number;
  left?: TreeNode;
  right?: TreeNode;
}

const tree: TreeNode = {
  value: 1,
  left: {
    value: 2,
    left: { value: 3 },
    right: { value: 4 }
  },
  right: { value: 5 }
};

✅ Use Case: File systems, organizational charts, UI components like menus.

8. Keyof and Lookup Types

Use keyof to get keys of a type, and lookup types to extract property types.

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

type UserKeys = keyof User;       // "id" | "name"
type IdType = User["id"];         // number

9. Infer Keyword

infer is used in conditional types to extract and reuse inferred types.

type ReturnType = T extends (...args: any[]) => infer R ? R : never;

type Func = () => string;
type Result = ReturnType; // string

✅ Use Case: Custom type helpers, like extracting result types of functions.

10. Utility Types

TypeScript ships with powerful utility types:

interface Task {
  id: number;
  title: string;
  completed?: boolean;
}

type PartialTask = Partial;     // All properties optional
type RequiredTask = Required;   // All properties required
type PickTitle = Pick; // Only 'title'
type OmitId = Omit;       // Exclude 'id'

✅ Use Case: Modify models without duplication, tailor types for APIs, forms, or components.

Conclusion

Advanced TypeScript features can help you build safer, scalable, and more expressive codebases. Whether you're working on frontend UI, backend APIs, or shared libraries, mastering these patterns will boost both confidence and productivity.