Skip to main content

Object Type Utilities

Object type utilities provide powerful tools for manipulating and transforming object types in TypeScript.

Basic Types

PropertyKey

Standard TypeScript property key type.

type PropertyKey = string | number | symbol;

AnyObject

Generic object type with flexible key-value pairs.

type AnyObject<T = any> = Record<PropertyKey, T>;

// Usage
type StringObject = AnyObject<string>; // Record<PropertyKey, string>
type NumberObject = AnyObject<number>; // Record<PropertyKey, number>

Value and Key Extraction

ValueOf

Extract all possible value types from an object type.

type ValueOf<T> = T[keyof T];

// Example
interface User {
id: number;
name: string;
active: boolean;
}

type UserValue = ValueOf<User>; // number | string | boolean

KeyOf

Extract all key types from an object (alias for keyof).

type KeyOf<T> = keyof T;

// Example
type UserKeys = KeyOf<User>; // "id" | "name" | "active"

Property Override

Generic

Override a specific property type in an object.

type Generic<R, K extends keyof R, T> = Omit<R, K> & Record<K, T>;

// Example
interface User {
id: number;
name: string;
createdAt: Date;
}

// Override createdAt to be a string
type UserWithStringDate = Generic<User, 'createdAt', string>;
// Result: { id: number; name: string; createdAt: string; }

Advanced Filtering

OmitByObject

Exclude properties from an object based on another object's structure.

type OmitByObject<T, U> = Omit<T, keyof U>;

// Example
interface FullUser {
id: number;
name: string;
email: string;
password: string;
}

interface SensitiveFields {
password: string;
}

type PublicUser = OmitByObject<FullUser, SensitiveFields>;
// Result: { id: number; name: string; email: string; }

Dependency Relationships

RequiredDependency

Create dependency relationships between object properties.

Omit<T, D> & (Partial<{ [P in K | D]: never }> | Required<Pick<T, K | D>>);

// Example
interface DatabaseConfig {
host?: string;
port?: number;
ssl?: boolean;
}

// When host is provided, port must also be provided
type SafeConfig = RequiredDependency<DatabaseConfig, 'host', 'port'>;

const config1: SafeConfig = { ssl: true }; // ✅ Valid
const config2: SafeConfig = { host: 'localhost', port: 3306 }; // ✅ Valid
const config3: SafeConfig = { host: 'localhost' }; // ❌ Error: port is required

Mutual Exclusion

MutuallyWithObject

Create mutually exclusive properties from an object type.

type MutuallyWithObject<T> = {
[K in keyof T]: Record<K, T[K]> & Partial<Record<Exclude<keyof T, K>, never>>;
}[keyof T];

// Example
interface AuthMethods {
token: string;
username: string;
apiKey: string;
}

type AuthMethod = MutuallyWithObject<AuthMethods>;

const auth1: AuthMethod = { token: 'abc123' }; // ✅ Valid
const auth2: AuthMethod = { username: 'john' }; // ✅ Valid
const auth3: AuthMethod = { token: 'abc', username: 'john' }; // ❌ Error: mutually exclusive

Mutually

Create mutual exclusion between two specific properties.

type Mutually<T, K extends keyof T, O extends keyof T>
= (T & Record<K, T[K]> & Partial<Record<O, never>>)
| (T & Record<O, T[O]> & Partial<Record<K, never>>);

// Example
interface PaymentOptions {
amount: number;
creditCard?: string;
paypal?: string;
}

type Payment = Mutually<PaymentOptions, 'creditCard', 'paypal'>;

const payment1: Payment = { amount: 100, creditCard: '1234' }; // ✅ Valid
const payment2: Payment = { amount: 100, paypal: 'user@example.com' }; // ✅ Valid
const payment3: Payment = { amount: 100, creditCard: '1234', paypal: 'user@example.com' }; // ❌ Error

Real-World Examples

API Configuration

import type { MutuallyWithObject, RequiredDependency } from 'typescript-api-pro';

interface APIConfig {
baseURL?: string;
timeout?: number;
retries?: number;
auth?: {
token?: string;
basic?: { username: string; password: string };
oauth?: { clientId: string; clientSecret: string };
};
}

// Ensure timeout and retries work together
type ReliableAPIConfig = RequiredDependency<APIConfig, 'timeout', 'retries'>;

// Ensure only one auth method is used
type AuthConfig = MutuallyWithObject<NonNullable<APIConfig['auth']>>;

Form Validation

interface FormField {
required?: boolean;
minLength?: number;
maxLength?: number;
pattern?: RegExp;
}

// When minLength is set, maxLength should also be considered
type LengthValidation = RequiredDependency<FormField, 'minLength', 'maxLength'>;

Component Props

interface ButtonProps {
variant?: 'primary' | 'secondary';
size?: 'small' | 'medium' | 'large';
loading?: boolean;
disabled?: boolean;
}

// Loading and disabled are mutually exclusive
type ButtonState = Mutually<ButtonProps, 'loading', 'disabled'>;