Skip to content

Instantly share code, notes, and snippets.

@DATADEER
Last active January 29, 2025 13:18
Show Gist options
  • Save DATADEER/95b0df310c8e8dab8f0eb79739298854 to your computer and use it in GitHub Desktop.
Save DATADEER/95b0df310c8e8dab8f0eb79739298854 to your computer and use it in GitHub Desktop.
All kinds of useful type helpers
/**
* Extracts the type of values in an object or array
*
* @example
* type Colors = {
* primary: string;
* secondary: string;
* };
*
* type ColorValue = ValueOf<Colors>; // string
*
* type Numbers = number[];
* type NumberValue = ValueOf<Numbers>; // number
*/
export type ValueOf<T> = T[keyof T];
/**
* Allows string literal autocomplete while still accepting any string
*
* @example
* type ButtonVariant = LooseAutocomplete<'primary' | 'secondary' | 'tertiary'>;
*
* // These all work:
* const button1: ButtonVariant = 'primary'; // autocompleted
* const button2: ButtonVariant = 'secondary'; // autocompleted
* const button3: ButtonVariant = 'custom'; // also valid
*/
export type LooseAutocomplete<T extends string> = T | (string & {});
/**
* Applies Omit<T, K> in a distributive way over union types
*
* @description
* This type helper ensures that when using Omit with a union type, the Omit operation
* is applied to each member of the union independently.
*
* @template T - The union type to distribute Omit over
* @template K - The keys to omit from each member of the union
*
* @example
* type Square = { kind: 'square'; size: number; color: string };
* type Circle = { kind: 'circle'; radius: number; color: string };
* type Shape = Square | Circle;
*
* // Regular Omit might not work as expected with discriminative unions
* type ShapeWithoutColor1 = Omit<Shape, 'color'>;
*
* // DistributiveOmit properly removes 'color' from each shape
* type ShapeWithoutColor2 = DistributiveOmit<Shape, 'color'>;
* // Result:
* // { kind: 'square'; size: number } | { kind: 'circle'; radius: number }
*/
export type DistributiveOmit<T, K extends keyof any> = T extends any
? Omit<T, K>
: never;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment