|
| 1 | +import { NonEmptyArray, NonEmptyReadonlyArray } from "./Array.js"; |
| 2 | +import { ReadonlyRecord } from "./Object.js"; |
| 3 | + |
1 | 4 | /** |
2 | 5 | * Helper function to ensure exhaustive matching in a switch statement. Throws |
3 | 6 | * an error if an unhandled case is encountered. |
@@ -31,8 +34,79 @@ export const exhaustiveCheck = (value: never): never => { |
31 | 34 | throw new Error(`exhaustiveCheck unhandled case: ${JSON.stringify(value)}`); |
32 | 35 | }; |
33 | 36 |
|
| 37 | +/** |
| 38 | + * Returns the input value unchanged. |
| 39 | + * |
| 40 | + * Useful as a default transformation, placeholder callback, or when a function |
| 41 | + * is required but no transformation is needed. |
| 42 | + * |
| 43 | + * ### Example |
| 44 | + * |
| 45 | + * ```ts |
| 46 | + * const values = [1, 2, 3]; |
| 47 | + * const same = values.map(identity); // [1, 2, 3] |
| 48 | + * |
| 49 | + * const getTransform = (shouldDouble: boolean) => |
| 50 | + * shouldDouble ? (x: number) => x * 2 : identity; |
| 51 | + * ``` |
| 52 | + */ |
34 | 53 | export const identity = <A>(a: A): A => a; |
35 | 54 |
|
| 55 | +/** |
| 56 | + * Casts an array, set, record, or map to its readonly counterpart. |
| 57 | + * |
| 58 | + * Zero runtime cost — returns the same value with a readonly type. Use this to |
| 59 | + * enforce immutability at the type level. Preserves {@link NonEmptyArray} as |
| 60 | + * {@link NonEmptyReadonlyArray}. |
| 61 | + * |
| 62 | + * ### Example |
| 63 | + * |
| 64 | + * ```ts |
| 65 | + * // Array literals become NonEmptyReadonlyArray |
| 66 | + * const items = readonly([1, 2, 3]); |
| 67 | + * // Type: NonEmptyReadonlyArray<number> |
| 68 | + * |
| 69 | + * // NonEmptyArray is preserved as NonEmptyReadonlyArray |
| 70 | + * const nonEmpty: NonEmptyArray<number> = [1, 2, 3]; |
| 71 | + * const readonlyNonEmpty = readonly(nonEmpty); |
| 72 | + * // Type: NonEmptyReadonlyArray<number> |
| 73 | + * |
| 74 | + * // Regular arrays become ReadonlyArray |
| 75 | + * const arr: Array<number> = getNumbers(); |
| 76 | + * const readonlyArr = readonly(arr); |
| 77 | + * // Type: ReadonlyArray<number> |
| 78 | + * |
| 79 | + * // Sets, Records, and Maps |
| 80 | + * const ids = readonly(new Set(["a", "b"])); |
| 81 | + * // Type: ReadonlySet<string> |
| 82 | + * |
| 83 | + * const users: Record<UserId, string> = { ... }; |
| 84 | + * const readonlyUsers = readonly(users); |
| 85 | + * // Type: ReadonlyRecord<UserId, string> |
| 86 | + * |
| 87 | + * const lookup = readonly(new Map([["key", "value"]])); |
| 88 | + * // Type: ReadonlyMap<string, string> |
| 89 | + * ``` |
| 90 | + * |
| 91 | + * @experimental |
| 92 | + */ |
| 93 | +export function readonly<T>(array: NonEmptyArray<T>): NonEmptyReadonlyArray<T>; |
| 94 | +export function readonly<T>(array: Array<T>): ReadonlyArray<T>; |
| 95 | +export function readonly<T>(set: Set<T>): ReadonlySet<T>; |
| 96 | +export function readonly<K, V>(map: Map<K, V>): ReadonlyMap<K, V>; |
| 97 | +export function readonly<K extends keyof any, V>( |
| 98 | + record: Record<K, V>, |
| 99 | +): ReadonlyRecord<K, V>; |
| 100 | +export function readonly<T, K extends keyof any, V>( |
| 101 | + value: Array<T> | Set<T> | Map<K, V> | Record<K, V>, |
| 102 | +): |
| 103 | + | ReadonlyArray<T> |
| 104 | + | ReadonlySet<T> |
| 105 | + | ReadonlyMap<K, V> |
| 106 | + | ReadonlyRecord<K, V> { |
| 107 | + return value; |
| 108 | +} |
| 109 | + |
36 | 110 | /** |
37 | 111 | * A function that delays computation and returns a value of type T. |
38 | 112 | * |
|
0 commit comments