@@ -179,7 +179,7 @@ import { pack } from "msgpackr";
179179import type { Brand } from "./Brand.js" ;
180180import { type RandomBytesDep } from "./Crypto.js" ;
181181import { isPlainObject } from "./Object.js" ;
182- import { err , getOrThrow , ok , Result , trySync } from "./Result.js" ;
182+ import { err , getOrNull , getOrThrow , ok , Result , trySync } from "./Result.js" ;
183183import { safelyStringifyUnknownValue } from "./String.js" ;
184184import type { Literal , Simplify , WidenLiteral } from "./Types.js" ;
185185import { IntentionalNever } from "./Types.js" ;
@@ -219,14 +219,6 @@ export interface Type<
219219 * constants)
220220 * - Application startup where failure should crash the program
221221 * - Test code with known valid inputs
222- * - Converting from trusted sources where validation failure indicates a
223- * programming error
224- *
225- * **When NOT to use:**
226- *
227- * - User input validation - use `from` and handle errors gracefully
228- * - Data from external APIs or files - use `from` for proper error handling
229- * - Library code that should return Results rather than throw
230222 *
231223 * ### Example
232224 *
@@ -249,6 +241,38 @@ export interface Type<
249241 */
250242 readonly orThrow : ( value : Input ) => T ;
251243
244+ /**
245+ * Creates `T` from an `Input` value, returning `null` if validation fails.
246+ *
247+ * This is a convenience method that combines `from` with `getOrNull`.
248+ *
249+ * **When to use:**
250+ *
251+ * - When you need to convert a validation result to a nullable value
252+ * - When the error is not important and you just want the value or nothing
253+ * - APIs that expect `T | null`
254+ *
255+ * ### Example
256+ *
257+ * ```ts
258+ * // ✅ Good: Optional user input
259+ * const age = PositiveInt.orNull(userInput);
260+ * if (age != null) {
261+ * console.log("Valid age:", age);
262+ * }
263+ *
264+ * // ✅ Good: Default fallback
265+ * const maxRetries = PositiveInt.orNull(config.retries) ?? 3;
266+ *
267+ * // ❌ Avoid: When you need to know why validation failed (use `from` instead)
268+ * const result = PositiveInt.from(userInput);
269+ * if (!result.ok) {
270+ * console.error(formatPositiveError(result.error));
271+ * }
272+ * ```
273+ */
274+ readonly orNull : ( value : Input ) => T | null ;
275+
252276 /**
253277 * Creates `T` from an unknown value.
254278 *
@@ -468,6 +492,7 @@ const createType = <
468492 | "is"
469493 | "from"
470494 | "orThrow"
495+ | "orNull"
471496 | typeof EvoluTypeSymbol
472497 | "Type"
473498 | "Input"
@@ -481,7 +506,8 @@ const createType = <
481506 name,
482507 is : ( value : unknown ) : value is T => definition . fromUnknown ( value ) . ok ,
483508 from : definition . fromUnknown ,
484- orThrow : ( value : Input ) : T => getOrThrow ( definition . fromUnknown ( value ) ) ,
509+ orThrow : ( value ) => getOrThrow ( definition . fromUnknown ( value ) ) ,
510+ orNull : ( value ) => getOrNull ( definition . fromUnknown ( value ) ) ,
485511 [ EvoluTypeSymbol ] : true ,
486512 Type : undefined as unknown as T ,
487513 Input : undefined as unknown as Input ,
0 commit comments