A comprehensive TypeScript utility type library providing essential type helpers for modern TypeScript development.
Typommon is a lightweight TypeScript library that offers a curated collection of utility types designed to enhance type safety and developer experience. The library focuses on practical type transformations that are commonly needed in real-world TypeScript applications, covering string manipulation, object transformations, number handling, and type composition utilities.
bun add --dev typommon
# or
npm install --save-dev typommon
import type {
PartialBy,
Prettify,
Numeric,
Alphanumeric
} from 'typommon';
// Make specific fields optional for updates
type User = { id: string; name: string; email: string };
type UserUpdate = PartialBy<User, 'name' | 'email'>;
// Result: { id: string; name?: string; email?: string }
// Clean up complex intersection types
type Complex = { id: string } & { createdAt: Date } & { updatedAt: Date };
type Clean = Prettify<Complex>;
// Better IntelliSense and readability
// Handle both numbers and bigints
function processValue(value: Numeric): string {
return value.toString();
}
// Validate alphanumeric input
function isValidId(id: string): id is Alphanumeric {
return /^[A-Za-z0-9]+$/.test(id);
}
import type { LetterUppercase, LetterLowercase, DigitCharacter, Alphanumeric } from 'typommon';
// Uppercase letters - useful for constants, enums, or validation
const firstLetter: LetterUppercase = 'A'; // ✅ Valid
const invalid: LetterUppercase = 'a'; // ❌ TypeScript error
// Lowercase letters - great for case-sensitive operations
const code: LetterLowercase = 'g'; // ✅ Valid
// Digit characters - perfect for parsing or validation
const seventh: DigitCharacter = '7'; // ✅ Valid
// Alphanumeric characters - ideal for ID validation, tokens, etc.
function isAlphanumeric(char: string): char is Alphanumeric {
return /[A-Za-z0-9]/.test(char);
}
// Real-world example: validating user input
function validateUsername(username: string): boolean {
return username.split('').every(char => isAlphanumeric(char));
}
import type { Writable } from 'typommon';
// Remove readonly modifiers - useful when you need to mutate objects
type Config = { readonly id: string; readonly flag: boolean };
type MutableConfig = Writable<Config>;
// Result: { id: string; flag: boolean }
// Real-world example: creating a mutable copy of immutable data
type ImmutableUser = { readonly id: string; readonly name: string; readonly email: string };
type EditableUser = Writable<ImmutableUser>;
function updateUser(user: EditableUser, updates: Partial<EditableUser>): EditableUser {
return { ...user, ...updates }; // Now we can spread and modify
}
import type { Numeric, Zero, NumberSafe } from 'typommon';
// Generic numeric operations - works with both number and bigint
function double(value: Numeric): Numeric {
return typeof value === 'bigint' ? value * 2n : value * 2;
}
double(10); // 20
double(10n); // 20n
// Zero type checking - useful for validation and guards
function isZero(value: Numeric): value is Zero {
return value === 0 || value === 0n;
}
// Safe number parsing - perfect for form inputs and API responses
function parseSafeNumber(value: NumberSafe): number {
return typeof value === 'string' ? parseFloat(value) : value;
}
parseSafeNumber("42"); // 42
parseSafeNumber(42); // 42
// Real-world example: handling user input from forms
function processFormData(data: { count: NumberSafe; price: NumberSafe }) {
const count = parseSafeNumber(data.count);
const price = parseSafeNumber(data.price);
return { count, price, total: count * price };
}
import type {
PartialBy,
PartialDeep,
PartialExcept,
PartialNullable,
PartialNullableBy,
PartialWithUndefined
} from 'typommon';
// Make specific keys optional - perfect for update operations
type User = { id: string; email: string; name: string };
type UserDraft = PartialBy<User, 'email' | 'name'>;
// Result: { id: string; email?: string; name?: string }
// Real-world example: API update endpoint
function updateUser(id: string, updates: UserDraft): User {
// Only email and name can be optional, id is always required
return { id, ...updates } as User;
}
// Deep partial (recursive) - great for nested object updates
type Settings = { theme: { mode: 'light' | 'dark'; accent: string } };
type SettingsPatch = PartialDeep<Settings>;
// Result: { theme?: { mode?: 'light' | 'dark'; accent?: string } }
// Partial except specific keys - ensure critical fields stay required
type MandatoryId = PartialExcept<User, 'id'>;
// Result: { id: string; email?: string; name?: string }
// Partial with null support - useful for database updates
type Profile = { bio: string; avatar: string };
type ProfilePatch = PartialNullable<Profile>;
// Result: { bio?: string | null; avatar?: string | null }
// Real-world example: clearing optional fields
function clearProfileField(profile: Profile, field: keyof ProfilePatch) {
return { ...profile, [field]: null };
}
// Partial nullable for specific keys - selective null handling
type Editable = PartialNullableBy<Profile, 'bio' | 'avatar'>;
// Result: { bio?: string | null; avatar?: string | null }
// Partial with explicit undefined - distinguish between omitted and undefined
type Flags = { featureA: boolean; featureB: boolean };
type FlagsPatch = PartialWithUndefined<Flags>;
// Result: { featureA?: boolean | undefined; featureB?: boolean | undefined }
import type { Prettify, Simplify, Expand } from 'typommon';
// Force TypeScript to display properties as plain object - improves IntelliSense
type WithMeta = { id: string } & { createdAt: Date };
type Readable = Prettify<WithMeta>;
// Result: { id: string; createdAt: Date }
// Real-world example: complex intersection types become readable
type BaseUser = { id: string; name: string };
type WithTimestamps = { createdAt: Date; updatedAt: Date };
type WithPermissions = { role: 'admin' | 'user'; permissions: string[] };
type User = Prettify<BaseUser & WithTimestamps & WithPermissions>;
// Clean IntelliSense instead of complex intersection
// Alias for compatibility with other libraries
type Simplified = Simplify<WithMeta>;
// Expand for variant types - great for discriminated unions
type Variant<T> = Expand<T & { kind: 'variant' }>;
type SuccessVariant = Variant<{ data: string }>;
// Result: { data: string; kind: 'variant' }
import type {
Dict,
DeepRequired,
Merge,
Assign,
KeysOfType
} from 'typommon';
// String-keyed dictionary - perfect for lookup tables and caches
type UserLookup = Dict<{ id: string; name: string }>;
// Result: { [key: string]: { id: string; name: string } }
// Real-world example: user cache
const userCache: UserLookup = {
'user1': { id: '1', name: 'John' },
'user2': { id: '2', name: 'Jane' }
};
// Deep required (recursive) - normalize partial data
type MaybeConfig = { theme?: { mode?: string; accent?: string } };
type StrictConfig = DeepRequired<MaybeConfig>;
// Result: { theme: { mode: string; accent: string } }
// Real-world example: API response normalization
function normalizeConfig(partial: MaybeConfig): StrictConfig {
return {
theme: {
mode: partial.theme?.mode ?? 'light',
accent: partial.theme?.accent ?? '#000000'
}
};
}
// Object merging - U overrides T properties
type Base = { id: string; role: 'user'; name: string };
type Override = { role: 'admin'; permissions: string[] };
type Result = Merge<Base, Override>;
// Result: { id: string; role: 'admin'; name: string; permissions: string[] }
// Object assignment - same as Merge, different naming
type Extra = { email: string; phone?: string };
type Assigned = Assign<Base, Extra>;
// Result: { id: string; role: 'user'; name: string; email: string; phone?: string }
// Keys of specific type - extract keys with specific value types
type User = { id: string; age: number; active: boolean; name: string };
type BooleanKeys = KeysOfType<User, boolean>;
// Result: 'active'
// Real-world example: form field validation
function validateBooleanFields<T>(obj: T, fields: KeysOfType<T, boolean>[]): boolean {
return fields.every(field => typeof obj[field] === 'boolean');
}
| Type |
Description |
Use Case |
LetterUppercase |
Uppercase ASCII letters (A-Z) |
Constants, enums, validation |
LetterLowercase |
Lowercase ASCII letters (a-z) |
Case-sensitive operations |
DigitCharacter |
Single digit characters (0-9) |
Parsing, validation |
Alphanumeric |
Union of letters and digits |
ID validation, tokens |
Writable<T> |
Removes readonly modifiers from T |
Object mutation, cloning |
| Type |
Description |
Use Case |
Numeric |
Union of number and bigint |
Generic numeric operations |
Zero |
Literal zero (0 | 0n) |
Zero validation, guards |
NumberSafe |
Number or string representation |
Form inputs, API responses |
| Type |
Description |
Use Case |
PartialBy<T, K> |
Makes selected keys optional |
Update operations, drafts |
PartialDeep<T> |
Recursively makes all properties optional |
Nested object updates |
PartialExcept<T, K> |
Makes all properties optional except selected keys |
Required field preservation |
PartialNullable<T> |
Makes properties optional and nullable |
Database updates, clearing fields |
PartialNullableBy<T, K> |
Makes selected keys optional and nullable |
Selective null handling |
PartialWithUndefined<T> |
Makes properties optional with explicit undefined |
Serialization, API contracts |
| Type |
Description |
Use Case |
Prettify<T> |
Forces TypeScript to display as plain object |
IntelliSense improvement |
Simplify<T> |
Alias for Prettify |
Library compatibility |
Expand<T> |
Alias for Prettify |
Variant types, discriminated unions |
| Type |
Description |
Use Case |
Dict<T> |
String-keyed dictionary type |
Lookup tables, caches |
DeepRequired<T> |
Recursively makes all properties required |
Data normalization |
Merge<T, U> |
Merges objects with U overriding T |
Object composition |
Assign<T, U> |
Alias for Merge |
Object assignment semantics |
KeysOfType<T, U> |
Extracts keys with values of type U |
Type-safe field operations |
MIT
meluiz - me@meluiz.com
GitHub