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

frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.

Repository SourceNeeds Review
160.9K94.2Kanthropics
Coding

remotion-best-practices

Use this skills whenever you are dealing with Remotion code to obtain the domain-specific knowledge.

Repository SourceNeeds Review
148.3K2.1Kremotion-dev
Coding

azure-ai

Service Use When MCP Tools CLI

Repository SourceNeeds Review
136.4K155microsoft
Coding

azure-deploy

AUTHORITATIVE GUIDANCE — MANDATORY COMPLIANCE

Repository SourceNeeds Review
136K155microsoft