Created
March 24, 2025 16:34
-
-
Save toridoriv/32e5d3760a75e60d5a7e0e19dcb140ea to your computer and use it in GitHub Desktop.
Utility types for simplifying TypeScript object types.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @module expand | |
* Utility types for simplifying TypeScript object types. | |
* | |
* Tested with TypeScript v5.8.2. | |
*/ | |
/** | |
* Represents a primitive data type in JavaScript. | |
* | |
* A primitive is a basic data type that is not an object and has no methods. | |
* Primitives are immutable, meaning their values cannot be changed once they are created. | |
* | |
* The available primitive types in JavaScript are: | |
* - string: Represents textual data, enclosed in single or double quotes. | |
* - number: Represents numeric values, including integers and floating-point numbers. | |
* - bigint: Represents integer values that are too large to be represented by a regular | |
* number. | |
* - boolean: Represents a logical value, either true or false. | |
* - symbol: Represents a unique identifier, often used as keys for object properties. | |
* - null: Represents a deliberate non-value or null value. | |
* - undefined: Represents a value that has not been assigned or is not defined. | |
*/ | |
export type Primitive = string | number | bigint | boolean | symbol | null | undefined; | |
/** | |
* Takes a type `T` and expands it recursively or one level deep based on the `recursively` option. | |
* | |
* If `recursively` is `true`, uses {@linkcode Expand.Recursive}, else it uses {@linkcode Expand.OneLevel}. | |
* | |
* The type `E` is used to specify types that should not be expanded, but returned as they are. The default | |
* exclusions can be checked in {@linkcode Expand.Exclusions}. | |
*/ | |
export type Expand< | |
T, | |
recursively extends boolean = false, | |
E = Expand.Exclusions, | |
> = recursively extends true ? Expand.Recursive<T, E> : Expand.OneLevel<T, E>; | |
// eslint-disable-next-line @typescript-eslint/no-redeclare | |
export namespace Expand { | |
export type Exclusions = | |
| ArrayBuffer | |
| Blob | |
| Date | |
| FormData | |
| Headers | |
| Map<any, any> | |
| Primitive | |
| ReadableStream<any> | |
| RegExp; | |
/** | |
* Takes a type `T` and expands it into an object type with the same properties as `T`. | |
* | |
* Replaces any properties and array elements in `T` with their expanded types, up to | |
* one level deep. | |
* | |
* `E` specifies types that should not be expanded but returned as-is. | |
*/ | |
export type OneLevel<T, E = Exclusions> = T extends E | |
? T | |
: T extends (...args: infer A) => infer R | |
? (...args: OneLevel<A, E>) => OneLevel<R, E> | |
: T extends Promise<infer U> | |
? Promise<OneLevel<U, E>> | |
: T extends object | |
? { [K in keyof T]: T[K] } | |
: T; | |
/** | |
* Takes a type `T` and expands it into an object type with the same properties as `T`. | |
* | |
* Replaces any properties and array elements in `T` with their expanded types, | |
* recursively. | |
* | |
* `E` specifies types that should not be expanded but returned as-is. | |
*/ | |
export type Recursive<T, E = Exclusions> = T extends E | |
? T | |
: T extends (...args: infer A) => infer R | |
? (...args: Recursive<A, E>) => Recursive<R, E> | |
: T extends Promise<infer U> | |
? Promise<Recursive<U, E>> | |
: T extends object | |
? { [K in keyof T]: Recursive<T[K], E> } | |
: T; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment