TypeScript's largest utility library providing 200+ type utilities for advanced type manipulation.
—
Built-in type testing utilities for validating type transformations and ensuring type correctness in ts-toolbelt operations.
Basic types representing test outcomes.
/**
* Represents a passing test (true condition)
*/
type Pass = 1;
/**
* Represents a failing test (false condition)
*/
type Fail = 0;Usage Examples:
import { Test } from "ts-toolbelt";
// Basic usage
type PassingTest = Test.Pass; // 1
type FailingTest = Test.Fail; // 0
// Conditional results
type TestResult<T> = T extends string ? Test.Pass : Test.Fail;
type StringTest = TestResult<string>; // 1 (Pass)
type NumberTest = TestResult<number>; // 0 (Fail)Validate that types match expected results.
/**
* Check if a type matches expected result with specified outcome
* @param Type - Actual type to test
* @param Expect - Expected type
* @param Outcome - Expected test outcome (Pass or Fail)
* @returns Type-level validation of the test
*/
declare function check<Type, Expect, Outcome extends Boolean>(
debug?: Equals<Equals<Type, Expect>, Outcome>
): Equals<Equals<Type, Expect>, Outcome>;Usage Examples:
import { Test, A, O, L } from "ts-toolbelt";
// Test type equality
Test.check<string, string, Test.Pass>(); // ✓ Pass - types match
Test.check<string, number, Test.Fail>(); // ✓ Pass - correctly expects failure
// Test.check<string, number, Test.Pass>(); // ✗ Compile error - test would fail
// Test ts-toolbelt operations
Test.check<
O.Pick<{ a: string; b: number; c: boolean }, "a" | "b">,
{ a: string; b: number },
Test.Pass
>(); // ✓ Pick operation works correctly
Test.check<
L.Head<[1, 2, 3]>,
1,
Test.Pass
>(); // ✓ Head operation works correctly
Test.check<
A.Equals<"hello", "hello">,
1,
Test.Pass
>(); // ✓ Equals operation works correctly
// Test complex transformations
type User = { name: string; age: number; email?: string };
type RequiredUser = O.Required<User>;
Test.check<
RequiredUser,
{ name: string; age: number; email: string },
Test.Pass
>(); // ✓ Required transformation works
// Test negative cases
Test.check<
O.Pick<User, "nonexistent">,
{},
Test.Pass
>(); // This would actually fail compilation due to invalid keyRun multiple tests together for comprehensive validation.
/**
* Run multiple type tests in batch
* @param checks - Array of test results (must all be Pass/1)
* @returns void if all tests pass
*/
declare function checks(checks: 1[]): void;Usage Examples:
import { Test, O, L, S, N } from "ts-toolbelt";
// Batch test multiple operations
Test.checks([
// Object operations
Test.check<O.Keys<{ a: 1; b: 2 }>, "a" | "b", Test.Pass>(),
Test.check<O.Values<{ a: 1; b: 2 }>, 1 | 2, Test.Pass>(),
Test.check<O.At<{ a: string }, "a">, string, Test.Pass>(),
// List operations
Test.check<L.Length<[1, 2, 3]>, 3, Test.Pass>(),
Test.check<L.Head<["a", "b"]>, "a", Test.Pass>(),
Test.check<L.Tail<[1, 2, 3]>, [2, 3], Test.Pass>(),
// String operations
Test.check<S.Length<"hello">, 5, Test.Pass>(),
Test.check<S.Split<"a,b,c", ",">, ["a", "b", "c"], Test.Pass>(),
// Number operations
Test.check<N.Add<2, 3>, 5, Test.Pass>(),
Test.check<N.Greater<5, 3>, 1, Test.Pass>(),
]);
// Test suite for specific functionality
const testObjectMerge = Test.checks([
Test.check<
O.Merge<{ a: 1 }, { b: 2 }>,
{ a: 1; b: 2 },
Test.Pass
>(),
Test.check<
O.Merge<{ a: 1; b: 2 }, { b: 3; c: 4 }>,
{ a: 1; b: 3; c: 4 },
Test.Pass
>(),
Test.check<
O.Merge<{}, { a: 1 }>,
{ a: 1 },
Test.Pass
>(),
]);
// Test suite for list transformations
const testListOperations = Test.checks([
Test.check<L.Append<[1, 2], 3>, [1, 2, 3], Test.Pass>(),
Test.check<L.Prepend<[2, 3], 1>, [1, 2, 3], Test.Pass>(),
Test.check<L.Reverse<[1, 2, 3]>, [3, 2, 1], Test.Pass>(),
Test.check<L.Concat<[1, 2], [3, 4]>, [1, 2, 3, 4], Test.Pass>(),
]);Complex testing scenarios for comprehensive validation.
Usage Examples:
import { Test, O, L, F, A } from "ts-toolbelt";
// Test generic type functions
type TestGeneric<T> = Test.check<
O.Pick<{ a: T; b: number }, "a">,
{ a: T },
Test.Pass
>;
type StringGenericTest = TestGeneric<string>; // ✓
type NumberGenericTest = TestGeneric<number>; // ✓
// Test conditional logic
type TestConditional<T> = T extends string
? Test.check<T, string, Test.Pass>
: Test.check<T, string, Test.Fail>;
type ConditionalStringTest = TestConditional<"hello">; // ✓
type ConditionalNumberTest = TestConditional<42>; // ✓
// Test complex transformations
type DeepObject = {
user: {
profile: {
name: string;
details: {
age: number;
};
};
};
};
const testDeepOperations = Test.checks([
Test.check<
O.At<DeepObject, "user">,
{ profile: { name: string; details: { age: number } } },
Test.Pass
>(),
Test.check<
A.Keys<DeepObject>,
"user",
Test.Pass
>(),
]);
// Test error cases (negative testing)
const testErrorCases = Test.checks([
// These should explicitly test for failure
Test.check<string, number, Test.Fail>(), // Different types
Test.check<{ a: 1 }, { a: 2 }, Test.Fail>(), // Different values
Test.check<[1, 2], [1, 2, 3], Test.Fail>(), // Different lengths
]);
// Test edge cases
const testEdgeCases = Test.checks([
// Empty types
Test.check<L.Length<[]>, 0, Test.Pass>(),
Test.check<O.Keys<{}>, never, Test.Pass>(),
Test.check<S.Length<"">, 0, Test.Pass>(),
// Never and unknown
Test.check<A.Equals<never, never>, 1, Test.Pass>(),
Test.check<A.Extends<never, any>, 1, Test.Pass>(),
// Union handling
Test.check<A.Keys<{ a: 1 } | { b: 2 }>, "a" | "b", Test.Pass>(),
]);
// Performance testing (ensuring operations complete)
const testPerformance = Test.checks([
// Large unions
Test.check<
A.Contains<1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10, 5>,
1,
Test.Pass
>(),
// Deep nesting
Test.check<
L.Length<[1, [2, [3, [4, [5]]]]]>,
2, // Only counts top level
Test.Pass
>(),
]);
// Regression tests
const testRegressions = Test.checks([
// Previous bug fixes
Test.check<O.Merge<{ a?: 1 }, { a: 2 }>, { a: 2 }, Test.Pass>(),
Test.check<L.At<[1, 2, 3], 1>, 2, Test.Pass>(),
Test.check<S.Replace<"hello", "l", "x">, "hexxo", Test.Pass>(),
]);Guidelines for effective type testing with ts-toolbelt.
Usage Examples:
import { Test } from "ts-toolbelt";
// 1. Test both positive and negative cases
const comprehensiveTest = Test.checks([
// Positive: what should work
Test.check<string, string, Test.Pass>(),
Test.check<1 | 2, number, Test.Fail>(), // Union doesn't extend specific type
// Negative: what should fail
Test.check<string, number, Test.Fail>(),
Test.check<{ a: 1; b: 2 }, { a: 1 }, Test.Fail>(), // Extra properties
]);
// 2. Test boundary conditions
const boundaryTest = Test.checks([
Test.check<[], never[], Test.Fail>(), // Empty array vs never array
Test.check<{}, Record<string, never>, Test.Fail>(), // Empty object variations
Test.check<unknown, any, Test.Fail>(), // Unknown vs any
]);
// 3. Test with realistic data structures
type ApiResponse<T> = {
success: boolean;
data: T;
meta: {
timestamp: number;
version: string;
};
};
const realWorldTest = Test.checks([
Test.check<
O.Pick<ApiResponse<string>, "success" | "data">,
{ success: boolean; data: string },
Test.Pass
>(),
Test.check<
O.At<ApiResponse<number>, "meta">,
{ timestamp: number; version: string },
Test.Pass
>(),
]);
// 4. Document test intent with descriptive names
type TestUserPermissions = Test.checks([
Test.check<
O.Has<{ read: true; write: false }, "admin">,
0, // Should not have admin permission
Test.Pass
>(),
Test.check<
O.Required<{ read?: boolean; write?: boolean }>,
{ read: boolean; write: boolean },
Test.Pass
>(),
]);// Test result types
type Pass = 1;
type Fail = 0;
type Boolean = 0 | 1;
// Internal equality checking (used by check function)
type Equals<A1, A2> = (<A>() => A extends A1 ? 1 : 0) extends (<A>() => A extends A2 ? 1 : 0) ? 1 : 0;Install with Tessl CLI
npx tessl i tessl/npm-ts-toolbelt