npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

ts-type-forge

v2.3.0

Published

[![npm version](https://img.shields.io/npm/v/ts-type-forge.svg)](https://www.npmjs.com/package/ts-type-forge) [![npm downloads](https://img.shields.io/npm/dm/ts-type-forge.svg)](https://www.npmjs.com/package/ts-type-forge) [![License](https://img.shields.

Downloads

4,126

Readme

ts-type-forge

npm version npm downloads License

ts-type-forge is a comprehensive TypeScript type utility library that provides powerful type-level operations with zero runtime cost. It enhances TypeScript development by offering advanced type manipulations, strict type checking utilities, and comprehensive type safety features.

Features

This library offers a comprehensive suite of type-level utilities, including:

  • Advanced Type Utilities: Enhanced versions of built-in types like StrictExclude, StrictOmit, ReadonlyRecord, and many more.
  • Compile-Time Type Checking: Assert type relationships at compile time with comprehensive condition types.
  • Branded Types: Extensive collection of branded number types (Int, Uint, SafeInt, FiniteNumber, etc.) for enhanced type safety.
  • Array and Tuple Utilities: Type-safe operations with List and Tuple namespaces for complex array manipulations.
  • Record Manipulation: Deep operations like DeepReadonly, DeepPartial, and advanced path-based record updates.
  • Type-Level Arithmetic: Integer operations, ranges (UintRange), and mathematical type computations.
  • Global Type Availability: No need for import statements when using Triple-Slash Directives.
  • Zero Runtime Cost: Pure type-level operations with no runtime dependencies.
  • Comprehensive Testing: Thoroughly tested for type correctness with custom type-testing utilities.

Installation

npm add --save-dev ts-type-forge

Or with other package managers:

# Yarn
yarn add --dev ts-type-forge

# pnpm
pnpm add --save-dev ts-type-forge

TypeScript Configuration

ts-type-forge works best with strict TypeScript settings:

{
    "compilerOptions": {
        "strict": true, // important
        "noUncheckedIndexedAccess": true, // important
        "noPropertyAccessFromIndexSignature": true, // important
        "noFallthroughCasesInSwitch": true,
        "noImplicitOverride": true,
        "noImplicitReturns": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "allowUnreachableCode": false,
        "allowUnusedLabels": false,
        "exactOptionalPropertyTypes": false
    }
}

How to use

There are two ways to use the types provided by ts-type-forge:

  1. Triple-Slash Directive (Recommended for global availability): Add /// <reference types="ts-type-forge" /> to any .ts file in your project (e.g., globals.d.ts or at the top of a frequently used file). This makes all types from ts-type-forge globally available without needing explicit imports.

    // src/globals.d.ts or any other .ts file
    /// <reference types="ts-type-forge" />
    
    // src/types/dice.ts
    // No import needed
    export type DiceValue = UintRange<1, 7>; // 1 | 2 | 3 | 4 | 5 | 6
  2. Explicit Imports: Alternatively, you can import types explicitly if you prefer more granular control or are not using triple-slash directives.

    // src/types/dice.ts
    import { type UintRange } from 'ts-type-forge';
    
    export type DiceValue = UintRange<1, 7>; // 1 | 2 | 3 | 4 | 5 | 6

Core Modules

🎯 Type Conditions and Predicates

Essential type-level conditional logic for advanced type operations.

  • Type Equality - TypeEq for exact type matching
  • Type Extensions - TypeExtends for subtype relationships
  • Union Detection - IsUnion for union type identification
  • Never Detection - IsNever for never type checking

🔧 Record and Object Types

Advanced object type manipulations with strict type safety.

  • Strict Operations - StrictOmit, StrictPick, StrictExclude with key validation
  • Deep Operations - DeepReadonly, DeepPartial, DeepRequired
  • Partial Utilities - PartiallyPartial, PartiallyOptional, PartiallyRequired
  • Record Paths - RecordPaths, RecordValueAtPath for type-safe property access

🔢 Branded Number Types

Comprehensive branded types for enhanced numeric type safety.

  • Basic Types - Int, Uint, SafeInt, FiniteNumber
  • Range Types - Int16, Int32, Uint16, Uint32
  • Constraint Types - PositiveInt, NonZeroInt, NonNegativeInt
  • Floating Point - Float32, Float64 with proper constraints

📋 Array and Tuple Operations

Type-safe array and tuple utilities with functional programming patterns.

  • Array Types - NonEmptyArray, ArrayOfLength, ArrayAtLeastLen
  • List Namespace - Comprehensive list operations (Head, Tail, Take, Skip, etc.)
  • Tuple Namespace - Type-safe tuple manipulations with compile-time guarantees

🧮 Type-Level Arithmetic

Mathematical operations performed entirely at the type level.

  • Integer Operations - Increment, Decrement, AbsoluteValue
  • Ranges - UintRange, UintRangeInclusive for precise numeric constraints
  • Comparisons - Max, Min for type-level comparisons

🌐 Constants and Primitives

Pre-defined type constants for common use cases.

  • Basic Constants - Primitive, FalsyValue, UnknownRecord
  • Web Types - HTTPRequestMethod for web development
  • Numeric Enums - MonthEnum, DateEnum, HoursEnum, etc.

Usage Examples

Here are detailed examples showcasing the power of ts-type-forge's type utilities.

For a comprehensive list of all available types and their detailed documentation, please refer to the API Reference section.

1. Type-Level Conditional Logic with TypeEq and TypeExtends

The type utilities allow you to perform complex type checking and assertions at compile time.

// No import needed if using triple-slash directive
// import type { TypeEq, TypeExtends } from 'ts-type-forge'; // if importing explicitly

type User = { id: number; name: string };
type Admin = { id: number; name: string; role: 'admin' };

// Check exact type equality
type IsExactMatch = TypeEq<User, Admin>; // false
type IsSameType = TypeEq<User, User>; // true

// Check type extension relationships
type AdminExtendsUser = TypeExtends<Admin, User>; // true
type UserExtendsAdmin = TypeExtends<User, Admin>; // false

// Use in conditional types
type GetUserType<T> =
    TypeExtends<T, Admin> extends true
        ? 'admin'
        : TypeExtends<T, User> extends true
          ? 'user'
          : 'unknown';

type AdminType = GetUserType<Admin>; // 'admin'
type UserType = GetUserType<User>; // 'user'

2. Deep Object Manipulation with DeepReadonly and DeepPartial

Transform nested object types with precise control over mutability and optionality.

type Config = {
    port: number;
    database: {
        host: string;
        port: number;
        credentials?: {
            user: string;
            pass: string;
        };
    };
    features: string[];
};

// Create a type where all properties, nested or not, are readonly
type ReadonlyConfig = DeepReadonly<Config>;

const config: ReadonlyConfig = {
    port: 8080,
    database: {
        host: 'localhost',
        port: 5432,
        credentials: {
            user: 'admin',
            pass: 'secret',
        },
    },
    features: ['featureA', 'featureB'],
};

// @ts-expect-error Cannot assign to 'port' because it is a read-only property
config.port = 8081;
// @ts-expect-error Cannot assign to 'host' because it is a read-only property
config.database.host = 'remote';
// @ts-expect-error Property 'push' does not exist on type 'readonly string[]'
config.features.push('featureC');

// Create a type where all properties are optional (useful for partial updates)
type PartialConfig = DeepPartial<Config>;

const partialUpdate: PartialConfig = {
    database: {
        host: 'new-host', // Only update specific fields
        // port and credentials are optional
    },
    // port and features are optional
};

3. Strict Type Operations with StrictOmit

Enhanced versions of built-in Omit utility that provide compile-time key validation.

type UserProfile = Readonly<{
    id: string;
    username: string;
    email: string;
    lastLogin: Date;
    bio?: string;
}>;

// StrictOmit ensures keys actually exist in the source type
type UserCreationData = StrictOmit<UserProfile, 'id' | 'lastLogin'>;

expectType<
    UserCreationData,
    // Result:
    Readonly<{
        username: string;
        email: string;
        bio?: string | undefined;
    }>
>('=');

const newUser: UserCreationData = {
    username: 'jane_doe',
    email: '[email protected]',
    bio: 'Software Developer', // Optional
};

// @ts-expect-error 'nonExistentKey' doesn't exist:
type InvalidOmit = StrictOmit<UserProfile, 'id' | 'nonExistentKey'>;

4. Array Type Safety with NonEmptyArray and List Operations

Guarantee array constraints and perform type-safe operations on collections.

type Post = Readonly<{
    title: string;
    content: string;
}>;

// A blog must have at least one post
type Blog = Readonly<{
    name: string;
    posts: NonEmptyArray<Post>; // Ensures posts array is never empty
}>;

const myBlog: Blog = {
    name: 'My Tech Journey',
    posts: [
        // This array must have at least one element
        { title: 'First Post', content: 'Hello world!' },
        { title: 'Understanding TypeScript', content: '...' },
    ],
};

// This would cause a type error:
const emptyBlog: Blog = {
    name: 'Empty Thoughts',
    // @ts-expect-error Source has 0 element(s) but target requires 1
    posts: [],
};

const getFirstPostTitle = (posts: NonEmptyArray<Post>): string =>
    posts[0].title; // Safe to access posts[0] - guaranteed to exist

// Advanced List operations at the type level
type NumberList = readonly [1, 2, 3, 4, 5];

type FirstElement = List.Head<NumberList>; // 1
type LastElement = List.Last<NumberList>; // 5
type WithoutFirst = List.Tail<NumberList>; // readonly [2, 3, 4, 5]
type FirstThree = List.Take<3, NumberList>; // readonly [1, 2, 3]
type Reversed = List.Reverse<NumberList>; // readonly [5, 4, 3, 2, 1]

// Combine operations
type LastThreeReversed = List.Reverse<List.TakeLast<3, NumberList>>; // readonly [5, 4, 3]

5. Type-Safe JSON Handling with JsonValue

Safely represent and work with JSON data structures.

const jsonString =
    '{"name": "Alice", "age": 30, "isAdmin": false, "tags": ["user", "active"], "metadata": null}';

try {
    // Cast the result of JSON.parse to JsonValue for type safety
    const parsedData = JSON.parse(jsonString) as JsonValue;

    // Use type guards to safely work with parsed data
    if (
        typeof parsedData === 'object' &&
        parsedData !== null &&
        !Array.isArray(parsedData)
    ) {
        // parsedData is now known to be JsonObject
        const jsonObj = parsedData as JsonObject;

        console.log(jsonObj['name']); // Access properties safely

        if (typeof jsonObj['age'] === 'number') {
            console.log(`Age: ${jsonObj['age']}`);
        }

        if (Array.isArray(jsonObj['tags'])) {
            for (const tag of jsonObj['tags']) {
                if (typeof tag === 'string') {
                    console.log(`Tag: ${tag}`);
                }
            }
        }
    } else if (Array.isArray(parsedData)) {
        // parsedData is a JSON array
        for (const item of parsedData) {
            console.log(item);
        }
    }
} catch (error) {
    console.error('Failed to parse JSON:', error);
}

// Define API response types using JsonValue
type ApiResponse = JsonObject &
    Readonly<{
        status: 'success' | 'error';
        data?: JsonValue;
        message?: string;
    }>;

6. Precise Numeric Ranges with UintRange and Branded Types

Define exact numeric constraints and enhance type safety with branded number types.

/**
 * Parse integer with constrained radix parameter
 * @param str A string to convert into a number
 * @param radix A value between 2 and 36 that specifies the base
 */
export const parseInteger = (str: string, radix?: UintRange<2, 37>): number =>
    Number.parseInt(str, radix);

// Alternative using inclusive range
export const parseIntegerInclusive = (
    str: string,
    radix?: UintRangeInclusive<2, 36>,
): number => Number.parseInt(str, radix);

// Valid usages:
parseInteger('10'); // radix defaults to 10
parseInteger('10', 2); // Binary
parseInteger('255', 16); // Hexadecimal
parseInteger('123', 36); // Maximum base

// Invalid usages (TypeScript will error):
// @ts-expect-error Argument of type '1' is not assignable to parameter of type 'UintRange<2, 37> | undefined'
parseInteger('10', 1);
// @ts-expect-error Argument of type '37' is not assignable to parameter of type 'UintRange<2, 37> | undefined'
parseInteger('10', 37);

// Branded types for additional safety
type UserId = Brand<number, 'UserId'>;
type ProductId = Brand<number, 'ProductId'>;

// Create branded values (you would typically have constructor functions)
declare const userId: UserId;
declare const productId: ProductId;

// Type-safe functions that can't mix up IDs
function getUserById(id: UserId): User | undefined {
    /* ... */
    return undefined;
}
function getProductById(id: ProductId): Product | undefined {
    /* ... */
    return undefined;
}

// @ts-expect-error Argument of type 'ProductId' is not assignable to parameter of type 'UserId'
getUserById(productId);

Modules Overview

The library is organized into logical modules for easy navigation and understanding:

  • condition/: Type predicates like TypeEq, TypeExtends, IsUnion, IsNever for conditional type logic.
  • record/: Object type utilities including StrictOmit, DeepReadonly, RecordPaths, and partial operations.
  • branded-types/: Comprehensive branded number types (Int, Uint, SafeInt, FiniteNumber, etc.) with range constraints.
  • tuple-and-list/: Array and tuple operations with List and Tuple namespaces for type-safe manipulations.
  • type-level-integer/: Mathematical operations like Increment, UintRange, AbsoluteValue performed at the type level.
  • constants/: Pre-defined constants like Primitive, FalsyValue, HTTPRequestMethod, and enum types.
  • others/: Utility types like JsonValue, Mutable, WidenLiteral, and helper functions.

Key Benefits

  • Type Safety: All utilities are designed with TypeScript's advanced type system, providing compile-time guarantees.
  • Zero Runtime Cost: Pure type-level operations with no runtime dependencies or overhead.
  • Comprehensive Coverage: From basic utilities to advanced type manipulations for complex scenarios.
  • Global Availability: Use triple-slash directives to make types available without explicit imports.
  • Extensive Testing: All utilities are thoroughly tested with custom type-testing framework.
  • Strict Validation: Enhanced versions of built-in types with compile-time key validation.

API Reference

For detailed information on all types, see the Full API Reference.

Overview of All Types (with source code links)

Important Notes

  • This library is type-level only with zero runtime dependencies and no runtime cost.
  • All types are designed to work seamlessly with TypeScript's strict mode settings.
  • The library supports both explicit imports and global type availability via triple-slash directives.
  • Custom type-testing utilities ensure all operations work correctly at compile time.

Runtime Type Guards with ts-data-forge

While ts-type-forge provides powerful compile-time type utilities, combining it with ts-data-forge unlocks runtime type validation capabilities that make your TypeScript applications even more robust.

ts-data-forge complements ts-type-forge by providing:

  • Type Guard Functions: Runtime validation for all the branded types defined in ts-type-forge
  • Type Assertions: Throw errors when values don't match expected types
  • Type Predicates: Safely narrow types at runtime with is* functions
  • JSON Validation: Runtime validation for JsonValue types
  • Array Guards: Validate NonEmptyArray and other array constraints at runtime

Example: Combining Type-Level and Runtime Safety

/// <reference types="ts-type-forge" />

// Runtime validation with ts-data-forge
import {
    isUint,
    expectType,
    assertNonEmptyArray,
    parseJsonValue,
    isRecord,
    hasKey,
} from 'ts-data-forge';

const numbers: readonly number[] = [1, 2, 3, 4, 5, 2, 3];

// Type-safe length checking
if (Arr.isArrayAtLeastLength(numbers, 2)) {
    // numbers is now guaranteed to have at least 3 elements
    expectType<typeof numbers, ArrayAtLeastLen<2, number>>('=');
    console.log(numbers[1]); // Array access to index 0, 1 is now safe even with noUncheckedIndexedAccess enabled
}

// Safe JSON parsing with type validation
const jsonString = '{"count": 42, "items": [1, 2, 3]}';
const data: JsonValue = parseJsonValue(jsonString); // Validates at runtime

// Use the data with confidence
if (isRecord(data) && hasKey(data, 'count')) {
    console.log(data.count); // Safe access
}

Benefits of Using Both Libraries Together

  1. Complete Type Safety: Compile-time guarantees with ts-type-forge + runtime validation with ts-data-forge
  2. API Boundary Protection: Validate external data (API responses, user input) at runtime
  3. Developer Experience: Same type names and conventions across both libraries
  4. Zero Runtime Cost Option: Use only ts-type-forge when runtime validation isn't needed
  5. Progressive Enhancement: Start with type-level safety, add runtime checks where needed

Install both libraries to get the full TypeScript type safety experience:

npm add ts-data-forge
npm add -D ts-type-forge

Compatibility Notes

This library requires TypeScript version 4.8 or higher for full compatibility with advanced type features.

Contributing

Contributions are welcome! Please see the repository's contribution guidelines for detailed information on how to contribute to this project.

License

Apache-2.0