type-fest

TypeScript utility types library with 180+ compile-time transformations for strict type operations, deep object manipulation, case conversions, and JSON-safe typing. Use when building type-safe APIs, config systems, state management, transforming external data schemas or when you are creating a new type.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "type-fest" with this command: npx skills add izidorome/skills/izidorome-skills-type-fest

type-fest: Advanced TypeScript Utility Types

type-fest provides 180+ compile-time utility types with zero runtime overhead for production TypeScript applications. Use it when built-in TypeScript utilities are insufficient for strict type operations, deep transformations, or complex type-level programming.

When to Use This Skill

Activate for:

  • API response/request type transformations (snake_case ↔ camelCase)
  • Deep configuration merging and partial updates
  • Immutable state management with readonly guarantees
  • JSON serialization type safety (Date → string, etc.)
  • Removing/selecting object properties with strict checking
  • Type-safe path access and property selection
  • Async function return type extraction
  • Conditional type operations

Skip for:

  • Runtime validation (use zod/yup/io-ts - type-fest is compile-time only)
  • Simple cases covered by built-in Partial, Pick, Omit
  • Runtime type guards (complement type-fest with runtime checks)

Installation

npm install type-fest

Import granularly for optimal tree-shaking:

import type {Except, Merge, PartialDeep, Jsonify} from 'type-fest';

Essential Utilities

Except<T, K> - Strict Property Removal

Use when: Removing keys from objects with compile-time verification.

Advantage over Omit: Catches typos - requires removed keys to actually exist.

import type {Except} from 'type-fest';

interface User {
  id: number;
  email: string;
  password: string;
  role: string;
}

// Remove sensitive fields for public API
type PublicUser = Except<User, 'password'>;
// Result: { id: number; email: string; role: string }

// Catches typos
type Bad = Except<User, 'pasword'>; // ✗ Error: 'pasword' doesn't exist

// Strict mode prevents re-adding omitted props
type StrictPublic = Except<User, 'password', {requireExactProps: true}>;

Merge<T, U> - Type-Safe Object Merging

Use when: Combining types where second type's properties override the first.

import type {Merge} from 'type-fest';

interface BaseConfig {
  host: string;
  port: number;
  timeout: number;
}

interface ProdOverrides {
  port: 3306;  // Literal type
  ssl: boolean;
  poolSize: number;
}

type ProdConfig = Merge<BaseConfig, ProdOverrides>;
// Result: { host: string; port: 3306; timeout: number; ssl: boolean; poolSize: number }

PartialDeep<T> - Recursive Optional Properties

Use when: Deep configuration objects or nested partial updates.

import type {PartialDeep} from 'type-fest';

interface AppSettings {
  theme: {
    colors: {
      primary: string;
      secondary: string;
    };
    fontSize: number;
  };
  features: {
    autoSave: boolean;
  };
}

// User can override any nested property
function updateSettings(updates: PartialDeep<AppSettings>) {
  // updates.theme?.colors?.primary is allowed
}

// Valid calls
updateSettings({theme: {colors: {primary: '#ff0000'}}});
updateSettings({features: {autoSave: false}});
updateSettings({theme: {fontSize: 16}});

Jsonify<T> - JSON Serialization Types

Use when: Typing API responses/requests that undergo JSON serialization.

What it does:

  • Datestring
  • Map, Set{}
  • Functions, undefined → removed
  • Recursively transforms nested types
import type {Jsonify} from 'type-fest';

interface Activity {
  userId: number;
  timestamp: Date;
  metadata: Map<string, string>;
  handler: () => void;
}

type ApiActivity = Jsonify<Activity>;
// Result: { userId: number; timestamp: string; metadata: {} }
// (handler and Map removed, Date → string)

async function fetchActivity(id: string): Promise<Activity> {
  const response = await fetch(`/api/activity/${id}`);
  const json: ApiActivity = await response.json();
  
  // Reconstruct proper types
  return {
    userId: json.userId,
    timestamp: new Date(json.timestamp), // string → Date
    metadata: new Map(),
    handler: () => console.log('loaded')
  };
}

ReadonlyDeep<T> - Deep Immutability

Use when: Enforcing immutability in state management, config objects.

import type {ReadonlyDeep} from 'type-fest';

interface State {
  users: Array<{
    id: number;
    profile: {name: string};
  }>;
}

type ImmutableState = ReadonlyDeep<State>;

const state: ImmutableState = {users: [{id: 1, profile: {name: 'John'}}]};

// All modification attempts cause errors
state.users.push(...); // ✗ Error
state.users[0].profile.name = 'Jane'; // ✗ Error

CamelCase<T> - Case Transformation

Use when: Converting API/database naming to JavaScript conventions.

import type {CamelCase} from 'type-fest';

interface DbUser {
  'user-id': number;
  'email_address': string;
  'created_at': string;
}

type AppUser = {
  [K in keyof DbUser as CamelCase<K>]: DbUser[K]
};
// Result: { userId: number; emailAddress: string; createdAt: string }

// Also available: SnakeCase, KebabCase, PascalCase

LiteralUnion<T, U> - Autocomplete-Preserving Unions

Use when: Creating extensible string enums that preserve IDE autocomplete.

Problem solved: 'red' | 'blue' | string loses autocomplete for 'red' and 'blue'.

import type {LiteralUnion} from 'type-fest';

// Without LiteralUnion - no autocomplete
type BadColor = 'red' | 'blue' | 'green' | string;

// With LiteralUnion - IDE autocompletes known values
type Color = LiteralUnion<'red' | 'blue' | 'green', string>;

function setTheme(color: Color) {
  // IDE suggests 'red', 'blue', 'green'
  // But also accepts '#FF5733', 'custom-color', etc.
}

AsyncReturnType<T> - Unwrap Promise Types

Use when: Typing async function results without manually unwrapping Promise.

import type {AsyncReturnType} from 'type-fest';

async function fetchUser(id: number) {
  const res = await fetch(`/api/users/${id}`);
  const data = await res.json();
  return {
    id,
    name: data.name,
    email: data.email,
    roles: data.roles as string[]
  };
}

type User = AsyncReturnType<typeof fetchUser>;
// Result: { id: number; name: any; email: any; roles: string[] }

// Use in callbacks
function processUsers(users: User[]) {
  users.forEach(u => console.log(u.name));
}

RequireAtLeastOne<T, K> - Conditional Required Props

Use when: Enforcing "at least one of these fields must be present".

import type {RequireAtLeastOne} from 'type-fest';

interface SearchParams {
  query?: string;
  userId?: number;
  email?: string;
  tags?: string[];
}

type ValidSearch = RequireAtLeastOne<SearchParams, 'query' | 'userId' | 'email'>;

function search(params: ValidSearch) {
  // At least one of: query, userId, or email is guaranteed
}

search({query: 'test'}); // ✓
search({userId: 123, tags: ['tag']}); // ✓
search({tags: ['tag']}); // ✗ Error: need query, userId, or email

ConditionalPick<T, Condition> - Select by Type

Use when: Extracting properties that match a specific type.

import type {ConditionalPick} from 'type-fest';

interface Endpoint {
  path: string;
  method: 'GET' | 'POST';
  timeout: number;
  retries: number;
  handler: (req: any) => Promise<any>;
  validate: (data: any) => boolean;
}

// Extract only functions
type EndpointFns = ConditionalPick<Endpoint, Function>;
// Result: { handler: ...; validate: ... }

// Extract only numbers
type EndpointNums = ConditionalPick<Endpoint, number>;
// Result: { timeout: number; retries: number }

Paths<T> - Type-Safe Property Paths

Use when: Building type-safe get/set utilities like lodash.

import type {Paths} from 'type-fest';

interface Config {
  database: {
    host: string;
    credentials: {
      user: string;
      password: string;
    };
  };
  api: {endpoint: string};
}

type ConfigPath = Paths<Config>;
// Union: 'database' | 'database.host' | 'database.credentials' | 
//        'database.credentials.user' | 'database.credentials.password' | 
//        'api' | 'api.endpoint'

function get<P extends ConfigPath>(config: Config, path: P): any {
  return path.split('.').reduce((obj: any, key) => obj?.[key], config);
}

get(config, 'database.credentials.user'); // ✓ Autocompletes
get(config, 'invalid.path'); // ✗ Type error

Simplify<T> - Flatten Intersection Types

Use when: Improving IDE hints and type assignability for composed types.

import type {Simplify} from 'type-fest';

type Position = {x: number; y: number};
type Size = {width: number; height: number};
type Styles = {color: string; opacity: number};

// Without Simplify - IDE shows: Position & Size & Styles
type Complex = Position & Size & Styles;

// With Simplify - IDE shows flat object
type Simple = Simplify<Position & Size & Styles>;
// Result: { x: number; y: number; width: number; height: number; color: string; opacity: number }

Common Patterns

API Client with Type Transformations

import type {Except, Jsonify, CamelCase, AsyncReturnType, ReadonlyDeep} from 'type-fest';

// External API (snake_case)
interface ApiUser {
  user_id: number;
  email_address: string;
  created_at: string;
}

// Internal app (camelCase)
type AppUser = {
  [K in keyof ApiUser as CamelCase<K>]: ApiUser[K]
};

// Public user (no sensitive data)
type PublicUser = Except<AppUser, 'emailAddress'>;

// Immutable state
type UserState = ReadonlyDeep<AppUser>;

class UserService {
  async getUser(id: number): Promise<AppUser> {
    const res = await fetch(`/api/users/${id}`);
    const data: Jsonify<ApiUser> = await res.json();
    
    return {
      userId: data.user_id,
      emailAddress: data.email_address,
      createdAt: data.created_at
    };
  }
}

type User = AsyncReturnType<UserService['getUser']>;

Configuration Management

import type {PartialDeep, Merge, Simplify} from 'type-fest';

interface BaseConfig {
  database: {host: string; port: number};
  api: {timeout: number};
}

interface EnvOverrides {
  database: {port: 3306};
  api: {retries: number};
}

// Merge and flatten
type FinalConfig = Simplify<Merge<BaseConfig, EnvOverrides>>;

function loadConfig(
  defaults: BaseConfig,
  overrides: PartialDeep<EnvOverrides>
): FinalConfig {
  // Deep merge logic
  return {...defaults, ...overrides} as FinalConfig;
}

Type-Safe Builders

import type {RequireAtLeastOne, Merge} from 'type-fest';

interface BaseRequest {
  timeout?: number;
  headers?: Record<string, string>;
}

interface RequiredFields {
  url: string;
}

type HttpRequest = RequireAtLeastOne<
  Merge<RequiredFields, BaseRequest>,
  'url'
>;

class HttpClient {
  request(config: HttpRequest) {
    // config.url guaranteed to exist
    fetch(config.url, {
      method: 'GET',
      headers: config.headers
    });
  }
}

Composition Strategy

Combine utilities for powerful type transformations:

import type {Merge, Simplify, PartialDeep, Except} from 'type-fest';

// Base + overrides + flatten
type CleanMerge<T, U> = Simplify<Merge<T, U>>;

// Remove sensitive + deep partial
type SafePartial<T> = PartialDeep<Except<T, 'password' | 'secret'>>;

// Chain multiple operations
type ComplexType = Simplify<
  Merge<
    Merge<BaseType, OverrideType>,
    FinalType
  >
>;

Important Gotchas

1. Runtime vs Compile-Time

CRITICAL: type-fest types don't validate at runtime.

// DON'T assume runtime safety
function process(data: Jsonify<MyType>) {
  const date = new Date(data.timestamp); // Could fail if data is malformed
}

// DO add runtime validation
function process(data: Jsonify<MyType>) {
  if (typeof data.timestamp !== 'string') {
    throw new Error('Invalid timestamp');
  }
  const date = new Date(data.timestamp);
}

2. Deep Type Nesting Limits

Avoid excessive PartialDeep/ReadonlyDeep nesting (3-4 levels max):

// DON'T
type Bad = PartialDeep<PartialDeep<DeepType>>;

// DO
type Good = PartialDeep<DeepType>;

3. Import Only What You Need

Tree-shaking works best with granular imports:

// DO
import type {Except, Merge} from 'type-fest';

// DON'T
import type * as TypeFest from 'type-fest';

4. LiteralUnion Scope

Don't use with already-narrow types:

// DON'T
type Bad = LiteralUnion<'active', 'active' | 'inactive'>;

// DO
type Good = LiteralUnion<'active' | 'inactive', string>;

Quick Reference

Needtype-fest UtilityAlternative
Remove keys (strict)Except<T, K>Omit<T, K> (lenient)
Merge objectsMerge<T, U>T & U (intersection)
Deep partialPartialDeep<T>Partial<T> (shallow)
Deep readonlyReadonlyDeep<T>Readonly<T> (shallow)
JSON-safe typesJsonify<T>Manual transformation
Case conversionCamelCase<T>Manual mapping
Extensible enumsLiteralUnion<T, U>T | U (no autocomplete)
Unwrap PromiseAsyncReturnType<T>Manual extraction
Require some keysRequireAtLeastOne<T, K>Custom conditional types
Pick by typeConditionalPick<T, C>Custom mapped types
Type pathsPaths<T>String literals
Flatten typesSimplify<T>Intersection types

Additional Utilities

Also available (180+ total):

  • RequireExactlyOne - Exactly one key required
  • SetRequired, SetOptional - Modify individual properties
  • SnakeCase, KebabCase, PascalCase - Other case conversions
  • IsEqual<T, U> - Type equality checking
  • Get<T, Path> - Type-safe property access
  • Opaque<T> - Branded types
  • PromiseValue<T> - Extract Promise value
  • Plus 170+ more specialized utilities

Browse the full list: https://github.com/sindresorhus/type-fest

Resources

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

Self Updater

⭐ OPEN SOURCE! GitHub: github.com/GhostDragon124/openclaw-self-updater ⭐ ONLY skill with Cron-aware + Idle detection! Auto-updates OpenClaw core & skills, an...

Registry SourceRecently Updated
1221Profile unavailable
Coding

ClawHub CLI Assistant

Use the ClawHub CLI to publish, inspect, version, update, sync, and troubleshoot OpenClaw skills from the terminal.

Registry SourceRecently Updated
1.9K2Profile unavailable
Coding

SkillTree Learning Progress Tracker

Track learning across topics like an RPG skill tree. Prerequisites, milestones, suggested next steps. Gamified learning path.

Registry SourceRecently Updated
910Profile unavailable
Coding

Speak Turbo - Talk to your Claude 90ms latency!

Give your agent the ability to speak to you real-time. Talk to your Claude! Ultra-fast TTS, text-to-speech, voice synthesis, audio output with ~90ms latency....

Registry SourceRecently Updated
4480Profile unavailable
type-fest | V50.AI