Skip to content

Instantly share code, notes, and snippets.

@DarkRoku12
Created May 21, 2025 21:32
Show Gist options
  • Save DarkRoku12/2d8cc899f977d387ba953e3756a4db1c to your computer and use it in GitHub Desktop.
Save DarkRoku12/2d8cc899f977d387ba953e3756a4db1c to your computer and use it in GitHub Desktop.
General TypeScript utilities.
export type Unpack<T> = T extends Array<infer U> // If array?
? U // Give the type inside the array.
: T extends ( ...args : any[] ) => infer U // If function?
? U // Give the type of the return.
: T extends Promise<infer U> // If promise?
? U // Give the type of the promise.
: T; // Else, just give the type.
export type ExactlyHelper<T , U> = T & Record<Exclude<keyof U , keyof T> , never>;
export type Exactly<T , U> = ExactlyHelper<T , U> extends Record<any , never> ? never : T;
export type MustExtend<T , U> = T extends U ? T : never;
export type MustExtendIf<T , U , R> = T extends U ? R : never;
export type MustNotExtend<T , U> = T extends U ? never : T;
export type MustNotExtendIf<T , U , R> = T extends U ? never : R;
export type Optional<T> = T | null | undefined;
export type Mutable<T> = { -readonly [P in keyof T] : T[P] };
export type PartialRecord<Key extends string | number | symbol , Type> = Partial<Record<Key , Type>>;
export type Defined<T> = { [P in keyof T] -?: NonNullable<T[P]> };
export type Nullable<T> = { [P in keyof T] ?: T[P] | null };
export type FilterStartsWith<Union , Begins extends string> = Union extends `${Begins}${infer _X}` ? Union : never;
export type FilterNotStartsWith<Union , Begins extends string> = Union extends `${Begins}${infer _X}` ? never : Union;
export type FilterEndsWith<Union , Ends extends string> = Union extends `${infer _X}${Ends}` ? Union : never;
export type FilterNotEndsWith<Union , Ends extends string> = Union extends `${infer _X}${Ends}` ? never : Union;
/** Useful for extracting null-ish properties (null | undefined) */
class WrapNever
{
private __hidden : void = 0 as any;
}
type NeverPropIfNullish<T = any> = {
[key in keyof T] : null extends T[key] ? T[key] | WrapNever : undefined extends T[key] ? T[key] | WrapNever : T[key];
};
//// Look for non-nullish properties ////
export type OnlyWrappedNever<T> = { [K in keyof T as WrapNever extends T[K] ? K : never] : Exclude<T[K] , WrapNever> };
export type OnlyNullish<T> = OnlyWrappedNever<NeverPropIfNullish<T>>;
export type OnlyNullishKeys<T> = keyof OnlyNullish<T>;
//// Look for nullish properties ////
export type OmitWrappedNever<T> = { [K in keyof T as WrapNever extends T[K] ? never : K] : T[K] };
export type OnlyNonNullish<T> = OmitWrappedNever<NeverPropIfNullish<T>>;
export type OnlyNonNullishKeys<T> = keyof OnlyNonNullish<T>;
//// Convert nullish properties to optional ////
export type NullToPartial<T> = OnlyNonNullish<T> & Partial<OnlyNullish<T>>;
export type AsPartial<T> = {
// Unwrap to auto-complete properties with VSCode.
[K in keyof NullToPartial<T>] : NullToPartial<T>[K];
};
//// String utilities /////
export type SpecificString<Literal extends string , Final = string extends Literal ? never : Literal> = Final;
export type AltSpecificString<Literal extends string , Alt , Final = string extends Literal ? Alt : Literal> = Final;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment