Type utilities provide powerful type-level transformations that help you manipulate and transform TypeScript types.
Core Type Utilities
Prettify
Flattens intersection types to improve IntelliSense display.
import type { Prettify } from '@zayne-labs/toolkit-type-helpers' ;
type User = { id : string };
type Timestamps = { createdAt : Date ; updatedAt : Date };
// Before: User & Timestamps (shows as intersection)
type UserWithTimestamps = User & Timestamps ;
// After: Clean, flattened type
type PrettyUser = Prettify < User & Timestamps >;
// Result: { id: string; createdAt: Date; updatedAt: Date; }
Type Signature type Prettify < TObject > = NonNullable < unknown > & { [ Key in keyof TObject ] : TObject [ Key ] };
DeepPrettify
Recursively prettifies nested object types.
import type { DeepPrettify } from '@zayne-labs/toolkit-type-helpers' ;
type Config = {
server : { host : string } & { port : number };
database : { url : string } & { pool : number };
};
type PrettyConfig = DeepPrettify < Config >;
// Result: {
// server: { host: string; port: number; };
// database: { url: string; pool: number; };
// }
Type Signature type DeepPrettify < TObject > =
TObject extends ( ... args : infer TParams ) => infer TReturn ? ( ... args : TParams ) => TReturn
: TObject extends object ? NonNullable < unknown > & { [ Key in keyof TObject ] : DeepPrettify < TObject [ Key ]> }
: TObject ;
Writeable
Removes readonly modifiers from object properties.
Shallow
Deep
Arrays & Tuples
import type { Writeable } from '@zayne-labs/toolkit-type-helpers' ;
type ReadonlyUser = {
readonly id : string ;
readonly profile : {
readonly name : string ;
};
};
type MutableUser = Writeable < ReadonlyUser >;
// Result: {
// id: string;
// profile: { readonly name: string }; // nested readonly preserved
// }
import type { Writeable } from '@zayne-labs/toolkit-type-helpers' ;
type ReadonlyUser = {
readonly id : string ;
readonly profile : {
readonly name : string ;
};
};
type FullyMutableUser = Writeable < ReadonlyUser , 'deep' >;
// Result: {
// id: string;
// profile: { name: string }; // nested readonly removed
// }
import type { Writeable } from '@zayne-labs/toolkit-type-helpers' ;
// Arrays
type MutableArray = Writeable < readonly string []>;
// Result: string[]
// Tuples
type MutableTuple = Writeable < readonly [ string , number ]>;
// Result: [string, number]
// Nested structures
type Complex = Writeable <
ReadonlyArray <{ readonly a : readonly string [] }>,
'deep'
>;
// Result: Array<{ a: string[] }>
Type Signature type WriteableLevel = "deep" | "shallow" ;
type Writeable < TObject , TLevel extends WriteableLevel = "shallow" > =
TObject extends ( ... args : infer TArgs ) => infer TReturn ? ( ... args : TArgs ) => Writeable < TReturn , TLevel >
: TObject extends ArrayOrObject ?
{
- readonly [ Key in keyof TObject ] : TLevel extends "deep" ?
NonNullable < TObject [ Key ]> extends ArrayOrObject ?
Writeable < TObject [ Key ], "deep" >
: TObject [ Key ]
: TObject [ Key ];
}
: TObject ;
UnmaskType
Displays the computed type instead of the type alias name.
import type { UnmaskType } from '@zayne-labs/toolkit-type-helpers' ;
type UserId = string ;
type UserName = string ;
// Without UnmaskType: hover shows "UserId" (alias name)
type User1 = { id : UserId ; name : UserName };
// With UnmaskType: hover shows actual structure
type User2 = UnmaskType <{ id : UserId ; name : UserName }>;
// Displays: { id: string; name: string; }
Type Signature type UnmaskType < TType > = { _ : TType }[ "_" ];
Utility Types
PrettyOmit & PrettyPick
Omit or pick properties with prettified results.
import type { PrettyOmit } from '@zayne-labs/toolkit-type-helpers' ;
type User = {
id : string ;
email : string ;
password : string ;
createdAt : Date ;
};
type PublicUser = PrettyOmit < User , 'password' >;
// Result: { id: string; email: string; createdAt: Date; }
DistributiveOmit & DistributivePick
Apply omit/pick operations across union types.
import type { DistributiveOmit , DistributivePick } from '@zayne-labs/toolkit-type-helpers' ;
type Circle = { type : 'circle' ; radius : number ; color : string };
type Square = { type : 'square' ; size : number ; color : string };
type Shape = Circle | Square ;
// Omit 'color' from each union member
type ShapeWithoutColor = DistributiveOmit < Shape , 'color' >;
// Result: { type: 'circle'; radius: number } | { type: 'square'; size: number }
// Pick 'type' from each union member
type ShapeType = DistributivePick < Shape , 'type' >;
// Result: { type: 'circle' } | { type: 'square' }
Type Signatures type DistributiveOmit < TObject , TKeysToOmit extends keyof TObject > =
TObject extends unknown ? Omit < TObject , TKeysToOmit > : never ;
type DistributivePick < TObject , TKeysToPick extends keyof TObject > =
TObject extends unknown ? Pick < TObject , TKeysToPick > : never ;
Advanced Utilities
NonFalsy
Removes falsy values from a type.
import type { NonFalsy } from '@zayne-labs/toolkit-type-helpers' ;
type MaybeValue = string | null | undefined | false | 0 | '' ;
type Value = NonFalsy < MaybeValue >;
// Result: string (all falsy types removed)
Awaitable
Represents a value that may or may not be wrapped in a Promise.
import type { Awaitable } from '@zayne-labs/toolkit-type-helpers' ;
function processData ( data : Awaitable < string >) {
// data can be string | Promise<string>
}
processData ( 'immediate value' );
processData ( Promise . resolve ( 'async value' ));
LiteralUnion
Provides autocomplete for literal types while allowing arbitrary values.
import type { LiteralUnion } from '@zayne-labs/toolkit-type-helpers' ;
type Theme = LiteralUnion < 'light' | 'dark' , string >;
// Autocomplete suggests 'light' and 'dark'
// But also accepts any string
const theme1 : Theme = 'light' ; // Autocompletes
const theme2 : Theme = 'custom-theme' ; // Also valid
Type Signature type LiteralUnion < TUnion extends TBase , TBase = string > =
TUnion | ( TBase & Record < never , never >);
AnyString & AnyNumber
Provide autocomplete for specific values while accepting any string/number.
import type { AnyString } from '@zayne-labs/toolkit-type-helpers' ;
// Can be any string, but shows as 'string' in errors
type CustomString = AnyString ;
const value : CustomString = 'anything' ;
Union Type Utilities
Extracts union types from objects, arrays, or sets.
Type Signature type InferredUnionVariant = "keys" | "values" ;
type ExtractUnion < TObject , TVariant extends InferredUnionVariant = "keys" > =
TObject extends Array < infer TUnion > | ReadonlyArray < infer TUnion > | Set < infer TUnion > ? TUnion
: TObject extends Record < infer TKeys , infer TValues > ?
TVariant extends "keys" ?
TKeys
: Prettify < Writeable < TValues , "deep" >>
: never ;
UnionToIntersection
Converts a union type to an intersection type.
import type { UnionToIntersection } from '@zayne-labs/toolkit-type-helpers' ;
type A = { a : string };
type B = { b : number };
type Union = A | B ;
type Intersection = UnionToIntersection < Union >;
// Result: { a: string } & { b: number }
UnionDiscriminator
Creates discriminated union types from an array of types.
import type { UnionDiscriminator } from '@zayne-labs/toolkit-type-helpers' ;
type Success = { status : 'success' ; data : string };
type Error = { status : 'error' ; error : string };
type Loading = { status : 'loading' };
type Result = UnionDiscriminator <[ Success , Error , Loading ]>;
// Each type has unique properties, shared ones become discriminators
Function & Callback Types
CallbackFn
Type for callback functions with specific parameters.
import type { CallbackFn } from '@zayne-labs/toolkit-type-helpers' ;
type UserCallback = CallbackFn < User , void >;
// Result: (...params: User[]) => void
const handleUsers : UserCallback = ( user1 , user2 , ... rest ) => {
// All parameters are typed as User
};
SelectorFn
Type for selector functions (commonly used in state management).
import type { SelectorFn } from '@zayne-labs/toolkit-type-helpers' ;
type AppState = {
user : { name : string };
posts : Post [];
};
const selectUserName : SelectorFn < AppState , string > = ( state ) => state . user . name ;
AnyFunction & AnyAsyncFunction
Generic function types that accept any arguments.
AnyFunction
AnyAsyncFunction
import type { AnyFunction } from '@zayne-labs/toolkit-type-helpers' ;
function executeCallback ( fn : AnyFunction < string >) {
return fn ();
}
executeCallback (() => 'result' );
Object Types
UnknownObject
Represents an object with unknown string keys.
import type { UnknownObject } from '@zayne-labs/toolkit-type-helpers' ;
function processObject ( obj : UnknownObject ) {
// obj is Record<string, unknown>
}
EmptyObject
Represents an empty object type.
import type { EmptyObject } from '@zayne-labs/toolkit-type-helpers' ;
type Config = EmptyObject ;
// Result: NonNullable<unknown> (represents {})
Array Types
NonEmptyArray
Ensures an array has at least one element.
import type { NonEmptyArray } from '@zayne-labs/toolkit-type-helpers' ;
function processItems ( items : NonEmptyArray < string >) {
const first = items [ 0 ]; // Always exists, no undefined check needed
}
// Valid
processItems ([ 'item1' , 'item2' ]);
// Error: Argument of type 'never[]' is not assignable
processItems ([]);
Testing Utilities
Expect & Equal
Utilities for type-level testing.
import type { Expect , Equal } from '@zayne-labs/toolkit-type-helpers' ;
type Test1 = Expect < Equal < string , string >>; // Pass
type Test2 = Expect < Equal < string , number >>; // Fail - type error
// Use in test files
type Tests = [
Expect < Equal < Writeable <{ readonly a : string }>, { a : string }>>,
Expect < Equal < Prettify <{ a : string } & { b : number }>, { a : string ; b : number }>>,
];
These utilities are commonly used with vitest or other testing frameworks to validate type transformations at compile time.
Best Practices
Use Prettify when:
Working with complex intersection types
Improving IntelliSense readability
Creating library types that users will consume
Debugging type issues in the IDE
Shallow vs Deep Writeable
Use shallow (default) when you only need to modify top-level properties
Use deep when working with deeply nested readonly structures
Deep transformations have a performance cost at compile time
LiteralUnion for Autocomplete
Use LiteralUnion when:
You want to suggest common values but allow custom ones
Building configuration objects with recommended options
Creating flexible APIs with good DX
See Also
Guards & Assertions Runtime type checking utilities
Enums Type-safe enum creation