Type Manipulation & Utility Types

The 50,000-Line Refactor With Zero Bugs

Friday morning. Product announced: "We're making all user fields optional for GDPR compliance. Users can delete any personal data."

I stared at our codebase: 50,000 lines. 217 components. 43 API endpoints. All assuming every User field was always present.

interface User {
  id: string;
  email: string;         // Now optional
  firstName: string;     // Now optional
  lastName: string;      // Now optional
  phoneNumber: string;   // Now optional
  address: string;       // Now optional
  birthDate: Date;       // Now optional
}

// Code everywhere like this:
function getUserFullName(user: User): string {
  return `${user.firstName} ${user.lastName}`;  // Will crash if undefined!
}

function sendEmail(user: User): void {
  mailService.send(user.email, 'Welcome!');  // Will crash if email deleted!
}

Manual refactoring would take weeks. I'd miss edge cases. Bugs would slip through.

Then I discovered TypeScript's utility types:

I ran the TypeScript compiler. 1,847 type errors. Every place that assumed fields existed.

I fixed them systematically. Took 2 days instead of 2 weeks. Deployed to production.

Result: Zero runtime errors. The compiler caught every edge case.

This article covers the type manipulation tools that saved our GDPR refactor.


keyof Type Operator

Get all keys of a type as a union.

Basic keyof

keyof with Generics


typeof Type Operator

Get the type of a value.

Basic typeof

typeof with Functions

typeof with Complex Values


Indexed Access Types

Access property types using bracket notation.

Basic Indexed Access

Indexed Access with Unions

Indexed Access with Arrays


Utility Types

TypeScript's built-in type manipulation tools.

Partial

Make all properties optional.

Required

Make all properties required.

Readonly

Make all properties readonly.

Pick<T, K>

Select specific properties.

Omit<T, K>

Exclude specific properties.

Record<K, T>

Create object type with specific keys and value type.

Exclude<T, U>

Remove types from union.

Extract<T, U>

Extract types from union.

NonNullable

Remove null and undefined from union.

ReturnType

Get function return type.

Parameters

Get function parameter types as tuple.


Mapped Types

Transform properties of existing types.

Basic Mapped Type

Mapped Type with Readonly

Mapped Type with Optional

Removing Modifiers


Conditional Types

Types that select based on conditions.

Basic Conditional Type

Conditional with Union

infer Keyword

Extract types within conditional types.

Nested infer


Template Literal Types

String manipulation at the type level.

Basic Template Literal

Template Literal with Union

Complex Template Literals


Real-World Patterns

1. Deep Partial

2. Type-Safe Event Emitter

3. Builder Pattern with Type State


Common Mistakes I Made

1. Overusing Utility Types

Bad:

Good:

2. Not Using Const Assertions

Bad:

Good:

3. Forgetting Distribution in Conditional Types

Bad:

Good:


Your Challenge

Build a type-safe form validation library:


Key Takeaways

  1. keyof - get all keys as union type

  2. typeof - get type from value

  3. Indexed access - extract property types

  4. Utility types - Partial, Required, Pick, Omit, Record, etc.

  5. Mapped types - transform object properties

  6. Conditional types - select types based on conditions

  7. Template literals - type-level string manipulation

  8. Keep it simple - don't over-complicate types


What I Learned

The GDPR refactor taught me: type manipulation is a force multiplier.

Without utility types:

With utility types:

The compiler became my refactoring partner. 1,847 type errors weren't failures – they were a comprehensive checklist of every place that needed attention.

Every error fixed was a prevented bug. Every type manipulation was automated code review.

TypeScript's type system didn't just check my code – it guided my refactor.

The lesson: advanced types aren't about showing off. They're about leveraging the compiler to do the grunt work.

Map 50 fields to optional? Write one type. Transform 100 API responses? Write one utility. The compiler applies it everywhere.

Type manipulation is how you make the impossible possible and the complex manageable.


Next: Classes and OOP

In the next article, we'll explore TypeScript's class features and object-oriented programming. You'll learn how access modifiers caught a critical security vulnerability before it reached production.

Last updated