Claude
Skills
Sign in
Back

typescript-utility-types

Included with Lifetime
$97 forever

Use when typeScript utility types, mapped types, and advanced type manipulation. Use when creating flexible, type-safe TypeScript code.

General

What this skill does


# TypeScript Utility Types

Master TypeScript's powerful type system including built-in utility types,
mapped types, conditional types, and advanced type manipulation techniques
for creating flexible, type-safe code.

## Built-in Utility Types

### Partial and Required

```typescript
interface User {
  id: string;
  name: string;
  email: string;
  age: number;
}

// Partial makes all properties optional
type PartialUser = Partial<User>;
// { id?: string; name?: string; email?: string; age?: number; }

function updateUser(id: string, updates: Partial<User>): User {
  const existingUser = getUser(id);
  return { ...existingUser, ...updates };
}

updateUser('123', { name: 'John' }); // Valid
updateUser('123', { age: 30 }); // Valid

// Required makes all properties required
interface OptionalConfig {
  host?: string;
  port?: number;
  timeout?: number;
}

type RequiredConfig = Required<OptionalConfig>;
// { host: string; port: number; timeout: number; }

function validateConfig(config: Required<OptionalConfig>): boolean {
  return config.host.length > 0 && config.port > 0;
}
```

### Pick and Omit

```typescript
interface Article {
  id: string;
  title: string;
  content: string;
  author: string;
  createdAt: Date;
  updatedAt: Date;
  views: number;
}

// Pick selects specific properties
type ArticlePreview = Pick<Article, 'id' | 'title' | 'author'>;
// { id: string; title: string; author: string; }

function displayPreview(article: ArticlePreview): void {
  console.log(`${article.title} by ${article.author}`);
}

// Omit removes specific properties
type ArticleWithoutDates = Omit<Article, 'createdAt' | 'updatedAt'>;
// { id: string; title: string; content: string; author: string; views: number; }

// Combining Pick and Omit
type ArticleMetadata = Pick<Article, 'id' | 'author' | 'createdAt'>;
type ArticleData = Omit<Article, 'id' | 'createdAt' | 'updatedAt'>;
```

### Readonly and Record

```typescript
// Readonly makes all properties readonly
type ReadonlyUser = Readonly<User>;

const user: ReadonlyUser = {
  id: '1',
  name: 'John',
  email: '[email protected]',
  age: 30,
};

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

// Deep readonly for nested objects
type DeepReadonly<T> = {
  readonly [P in keyof T]: T[P] extends object
    ? DeepReadonly<T[P]>
    : T[P];
};

// Record creates an object type with specific keys and value type
type UserRole = 'admin' | 'editor' | 'viewer';

type RolePermissions = Record<UserRole, string[]>;
// { admin: string[]; editor: string[]; viewer: string[]; }

const permissions: RolePermissions = {
  admin: ['read', 'write', 'delete'],
  editor: ['read', 'write'],
  viewer: ['read'],
};

// Record with complex types
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type RouteHandler = (req: Request) => Response;

type RouteHandlers = Record<HttpMethod, RouteHandler>;
```

### Extract and Exclude

```typescript
type Status = 'pending' | 'approved' | 'rejected' | 'cancelled';

// Extract types that are assignable to a condition
type CompletedStatus = Extract<Status, 'approved' | 'rejected'>;
// 'approved' | 'rejected'

// Exclude types that are assignable to a condition
type ActiveStatus = Exclude<Status, 'approved' | 'rejected' | 'cancelled'>;
// 'pending'

// Practical example
type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'square'; side: number }
  | { kind: 'rectangle'; width: number; height: number };

type CircularShape = Extract<Shape, { kind: 'circle' }>;
// { kind: 'circle'; radius: number }

type NonCircularShape = Exclude<Shape, { kind: 'circle' }>;
// { kind: 'square'; side: number } | { kind: 'rectangle'; width: number; height: number }
```

### ReturnType and Parameters

```typescript
function createUser(name: string, age: number): User {
  return {
    id: generateId(),
    name,
    age,
    email: `${name.toLowerCase()}@example.com`,
  };
}

// ReturnType extracts the return type of a function
type UserFromFunction = ReturnType<typeof createUser>;
// User

// Parameters extracts parameter types as a tuple
type CreateUserParams = Parameters<typeof createUser>;
// [name: string, age: number]

// Using with generic functions
function processData<T>(data: T[]): { count: number; items: T[] } {
  return { count: data.length, items: data };
}

type ProcessResult = ReturnType<typeof processData<User>>;
// { count: number; items: User[] }
```

## Mapped Types

### Basic Mapped Types

```typescript
// Create a type where all properties are boolean
type Flags<T> = {
  [P in keyof T]: boolean;
};

type UserFlags = Flags<User>;
// { id: boolean; name: boolean; email: boolean; age: boolean; }

// Create a type where all properties are nullable
type Nullable<T> = {
  [P in keyof T]: T[P] | null;
};

type NullableUser = Nullable<User>;
// { id: string | null; name: string | null; email: string | null; age: number | null; }

// Create a type where all properties are functions
type Getters<T> = {
  [P in keyof T as `get${Capitalize<string & P>}`]: () => T[P];
};

type UserGetters = Getters<User>;
// { getId: () => string; getName: () => string; getEmail: () => string; getAge: () => number; }
```

### Mapped Type Modifiers

```typescript
// Remove readonly modifier
type Mutable<T> = {
  -readonly [P in keyof T]: T[P];
};

interface ReadonlyPerson {
  readonly name: string;
  readonly age: number;
}

type MutablePerson = Mutable<ReadonlyPerson>;
// { name: string; age: number; }

// Remove optional modifier
type Concrete<T> = {
  [P in keyof T]-?: T[P];
};

interface OptionalUser {
  name?: string;
  age?: number;
}

type ConcreteUser = Concrete<OptionalUser>;
// { name: string; age: number; }

// Add optional modifier
type Optional<T> = {
  [P in keyof T]+?: T[P];
};
```

### Advanced Mapped Types

```typescript
// Transform property types
type Promisify<T> = {
  [P in keyof T]: Promise<T[P]>;
};

type AsyncUser = Promisify<User>;
// { id: Promise<string>; name: Promise<string>; email: Promise<string>; age: Promise<number>; }

// Wrap values in objects
type Boxed<T> = {
  [P in keyof T]: { value: T[P] };
};

type BoxedUser = Boxed<User>;
// { id: { value: string }; name: { value: string }; ... }

// Create proxy type
type Proxy<T> = {
  get(): T;
  set(value: T): void;
};

type ProxiedProperties<T> = {
  [P in keyof T]: Proxy<T[P]>;
};
```

## Conditional Types

### Basic Conditional Types

```typescript
// T extends U ? X : Y
type IsString<T> = T extends string ? true : false;

type Test1 = IsString<string>; // true
type Test2 = IsString<number>; // false

// Nested conditionals
type TypeName<T> =
  T extends string ? 'string' :
  T extends number ? 'number' :
  T extends boolean ? 'boolean' :
  T extends undefined ? 'undefined' :
  T extends Function ? 'function' :
  'object';

type T0 = TypeName<string>; // 'string'
type T1 = TypeName<number>; // 'number'
type T2 = TypeName<() => void>; // 'function'
```

### Distributive Conditional Types

```typescript
// Conditional types distribute over union types
type ToArray<T> = T extends any ? T[] : never;

type StrOrNumArray = ToArray<string | number>;
// string[] | number[] (not (string | number)[])

// Non-distributive version
type ToArrayNonDist<T> = [T] extends [any] ? T[] : never;

type StrOrNumArrayNonDist = ToArrayNonDist<string | number>;
// (string | number)[]

// Filter out null and undefined
type NonNullable<T> = T extends null | undefined ? never : T;

type MaybeString = string | null | undefined;
type DefinitelyString = NonNullable<MaybeString>; // string
```

### Inferring Types with infer

```typescript
// Infer return type
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

function example(): { x: number } {
  return { x: 42 };
}

type ExampleReturn = GetReturnType<typeof example>;
// { x: number }

// Infer array element type
type Flatten<T> = T extends Array<infer U> ? U : T;

type Str = Flatten<string[]>; // string
type Num = Flatten<number>; // number

// Infer 

Related in General