nalloc 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/types.d.ts CHANGED
@@ -15,6 +15,7 @@ export type Some<T> = ValueType<T> & {
15
15
  export type None = NoneValueType & {
16
16
  readonly [SOME_BRAND]: false;
17
17
  };
18
+ export type UnOption<V, T extends Option<V>> = T extends Some<V> ? V : None;
18
19
  /** Constant representing None. Use this instead of null/undefined for clarity. */
19
20
  export declare const NONE: None;
20
21
  /** Shared frozen empty array to avoid allocations. */
package/build/types.js CHANGED
@@ -25,10 +25,10 @@ function ResultErrorCtor(error) {
25
25
  }
26
26
  ResultErrorCtor.prototype[ERR_BRAND] = true;
27
27
  export function isOk(result) {
28
- return !result?.[ERR_BRAND];
28
+ return typeof result !== 'object' || result === null || !result[ERR_BRAND];
29
29
  }
30
30
  export function isErr(result) {
31
- return result?.[ERR_BRAND] === true;
31
+ return typeof result === 'object' && result !== null && result[ERR_BRAND] === true;
32
32
  }
33
33
  export function okUnchecked(value) {
34
34
  return value;
@@ -43,10 +43,10 @@ export function err(error) {
43
43
  return new ResultErrorCtor(error);
44
44
  }
45
45
  export function isThenable(value) {
46
- return typeof value?.then === 'function';
46
+ return (typeof value === 'object' || typeof value === 'function') && value !== null && typeof value.then === 'function';
47
47
  }
48
48
  export function isSync(value) {
49
- return typeof value?.then !== 'function';
49
+ return !(typeof value === 'object' || typeof value === 'function') || value === null || typeof value.then !== 'function';
50
50
  }
51
51
 
52
52
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["/** Values that represent None (absence of a value). */\nexport type NoneValueType = null | undefined | void;\n\n/** Widens literal types to their base types for better type inference. */\nexport type Widen<T> = T extends string\n ? string\n : T extends number\n ? number\n : T extends boolean\n ? boolean\n : T extends bigint\n ? bigint\n : T extends symbol\n ? symbol\n : T;\n\n/** Widens never to unknown, otherwise preserves the type. */\nexport type WidenNever<T> = [T] extends [never] ? unknown : T;\n\n/** Excludes None values from a type, leaving only valid Some values. */\nexport type ValueType<T> = Exclude<T, NoneValueType>;\n\nexport declare const SOME_BRAND: unique symbol;\n\n/** Represents a value that is present. The value itself is the Some - no wrapper object. */\nexport type Some<T> = ValueType<T> & { readonly [SOME_BRAND]: true };\n\n/** Represents the absence of a value (null or undefined). */\nexport type None = NoneValueType & { readonly [SOME_BRAND]: false };\n\n/** Constant representing None. Use this instead of null/undefined for clarity. */\nexport const NONE = undefined as None;\n\n/** Shared frozen empty array to avoid allocations. */\nexport const EMPTY: readonly unknown[] = Object.freeze([]);\n\n/** A value that may or may not be present. Some(T) is the value itself; None is null/undefined. */\nexport type Option<T> = Some<ValueType<T>> | None;\n\n/** Extracts the value type from an Option type. */\nexport type OptionValue<TOption> = TOption extends Option<infer TValue> ? TValue : never;\n\n/** Type predicate: true if T is an Option type. */\nexport type IsOption<T> = T extends Option<any> ? true : false;\n\n/** Infers the Some type from a value, preserving the inner type. */\nexport type InferSome<T> = T extends Some<infer TValue> ? Some<ValueType<TValue>> : never;\n\n/**\n * Checks if an Option contains a value (is Some).\n * @param opt - The Option to check\n * @returns true if the Option is Some, false if None\n * @example\n * isSome(42) // true\n * isSome(null) // false\n * isSome(undefined) // false\n */\nexport function isSome<T>(opt: Some<T>): true;\nexport function isSome(opt: None): false;\nexport function isSome<T>(opt: unknown): opt is Some<T>;\nexport function isSome(opt: unknown): boolean {\n return opt !== null && opt !== undefined;\n}\n\n/**\n * Checks if an Option is None (absent).\n * @param opt - The Option to check\n * @returns true if the Option is None, false if Some\n * @example\n * isNone(null) // true\n * isNone(undefined) // true\n * isNone(42) // false\n */\nexport function isNone<T>(opt: Some<T>): false;\nexport function isNone(opt: None): true;\nexport function isNone(opt: unknown): opt is None;\nexport function isNone(opt: unknown): boolean {\n return opt === null || opt === undefined;\n}\n\n/**\n * Creates an Option from a nullable value. Returns None for null/undefined, Some otherwise.\n * @param value - The value to wrap\n * @returns Some(value) if value is non-null, None otherwise\n * @example\n * optionOf(42) // Some(42)\n * optionOf(null) // None\n * optionOf(undefined) // None\n */\nexport function optionOf(value: null): None;\nexport function optionOf(value: undefined): None;\nexport function optionOf<T>(value: T): T extends NoneValueType ? None : Some<T>;\nexport function optionOf<T>(value: T): Option<T> {\n return isNone(value as Option<T>) ? NONE : (value as Some<T>);\n}\n\nexport function someUnchecked<T>(value: T): Some<ValueType<T>> {\n return value as Some<ValueType<T>>;\n}\n\n/**\n * Creates a Some value with runtime validation.\n * @param value - The value to wrap\n * @returns The value typed as Some\n * @throws TypeError if value is null or undefined\n * @example\n * some(42) // Some(42)\n */\nexport function some<T>(value: ValueType<T>): Some<ValueType<T>> {\n if (value === null || value === undefined) {\n throw new TypeError('some() requires a non-nullable value');\n }\n return someUnchecked(value);\n}\n\n/** Constant representing None. Alias for NONE. */\nexport const none: None = NONE;\n\ndeclare const OK_BRAND: unique symbol;\n\n/** Represents a successful Result value. The value itself is the Ok - no wrapper object. */\nexport type Ok<T> = T & { readonly [OK_BRAND]: true };\n\nconst ERR_BRAND = Symbol.for('nalloc.ResultError');\n\ninterface ResultErrorShape<E> {\n readonly error: E;\n readonly [ERR_BRAND]: true;\n}\n\nfunction ResultErrorCtor<E>(this: ResultErrorShape<E>, error: E): void {\n (this as { error: E }).error = error;\n}\n(ResultErrorCtor.prototype as { [ERR_BRAND]: true })[ERR_BRAND] = true;\n\n/** The error wrapper type used internally. */\nexport type ResultError<E> = ResultErrorShape<E>;\n\n/** Represents a failed Result containing an error. */\nexport type Err<E> = ResultError<E>;\n\n/** A value that is either successful (Ok) or failed (Err). Ok is the value itself; Err wraps the error. */\nexport type Result<T, E> = Ok<T> | Err<E>;\n\n/** Extracts the success value type from a Result type. */\nexport type ResultValue<TResult> = TResult extends Result<infer TValue, any> ? TValue : never;\n\n/** Extracts the error type from a Result type. */\nexport type ResultErrorType<TResult> = TResult extends Result<any, infer TError> ? TError : never;\n\n/** Type predicate: true if T is a Result type. */\nexport type IsResult<T> = T extends Result<any, any> ? true : false;\n\n/** Infers the Err type from a value, preserving the error type. */\nexport type InferErr<T> = T extends Err<infer TError> ? Err<TError> : never;\n\n/**\n * Checks if a Result is Ok (successful).\n * @param result - The Result to check\n * @returns true if the Result is Ok, false if Err\n * @example\n * isOk(42) // true (Ok value)\n * isOk(err('fail')) // false\n */\nexport function isOk<T>(result: Ok<T>): true;\nexport function isOk<E>(result: Err<E>): false;\nexport function isOk<T, E>(result: Result<T, E>): result is Ok<T>;\nexport function isOk(result: unknown): boolean;\nexport function isOk(result: unknown): boolean {\n return !(result as Record<symbol, unknown>)?.[ERR_BRAND];\n}\n\n/**\n * Checks if a Result is Err (failed).\n * @param result - The Result to check\n * @returns true if the Result is Err, false if Ok\n * @example\n * isErr(err('fail')) // true\n * isErr(42) // false (Ok value)\n */\nexport function isErr<E>(result: Err<E>): true;\nexport function isErr(result: Ok<unknown>): false;\nexport function isErr<T, E>(result: Result<T, E>): result is Err<E>;\nexport function isErr(result: unknown): result is Err<unknown>;\nexport function isErr(result: unknown): boolean {\n return (result as Record<symbol, unknown>)?.[ERR_BRAND] === true;\n}\n\nexport function okUnchecked<T>(value: T): Ok<T> {\n return value as Ok<T>;\n}\n\n/**\n * Creates an Ok value with runtime validation.\n * @param value - The success value\n * @returns The value typed as Ok\n * @throws TypeError if value is an Err\n * @example\n * ok(42) // Ok(42)\n */\nexport function ok<T>(value: T): Ok<T> {\n if (isErr(value)) {\n throw new TypeError('ok() cannot wrap an Err value');\n }\n return okUnchecked(value);\n}\n\n/**\n * Creates an Err value wrapping an error.\n * @param error - The error value\n * @returns An Err containing the error\n * @example\n * err('something went wrong') // Err('something went wrong')\n * err(new Error('failed')) // Err(Error)\n */\nexport function err<E>(error: E): Err<E> {\n return new (ResultErrorCtor as unknown as new (error: E) => Err<E>)(error);\n}\n\n/** A value that may or may not be a Promise. */\nexport type MaybePromise<T> = T | Promise<T> | PromiseLike<T>;\n\n/**\n * Checks if a value is a thenable (has a .then method).\n * @param value - The value to check\n * @returns true if value is a PromiseLike\n */\nexport function isThenable<T>(value: MaybePromise<T>): value is PromiseLike<T> {\n return typeof (value as PromiseLike<T>)?.then === 'function';\n}\n\n/**\n * Checks if a value is synchronous (not a thenable).\n * @param value - The value to check\n * @returns true if value is not a PromiseLike\n */\nexport function isSync<T>(value: MaybePromise<T>): value is T {\n return typeof (value as PromiseLike<T>)?.then !== 'function';\n}\n"],"names":["NONE","undefined","EMPTY","Object","freeze","isSome","opt","isNone","optionOf","value","someUnchecked","some","TypeError","none","ERR_BRAND","Symbol","for","ResultErrorCtor","error","prototype","isOk","result","isErr","okUnchecked","ok","err","isThenable","then","isSync"],"mappings":"AA+BA,OAAO,MAAMA,OAAOC,UAAkB;AAGtC,OAAO,MAAMC,QAA4BC,OAAOC,MAAM,CAAC,EAAE,EAAE;AA0B3D,OAAO,SAASC,OAAOC,GAAY;IACjC,OAAOA,QAAQ,QAAQA,QAAQL;AACjC;AAcA,OAAO,SAASM,OAAOD,GAAY;IACjC,OAAOA,QAAQ,QAAQA,QAAQL;AACjC;AAcA,OAAO,SAASO,SAAYC,KAAQ;IAClC,OAAOF,OAAOE,SAAsBT,OAAQS;AAC9C;AAEA,OAAO,SAASC,cAAiBD,KAAQ;IACvC,OAAOA;AACT;AAUA,OAAO,SAASE,KAAQF,KAAmB;IACzC,IAAIA,UAAU,QAAQA,UAAUR,WAAW;QACzC,MAAM,IAAIW,UAAU;IACtB;IACA,OAAOF,cAAcD;AACvB;AAGA,OAAO,MAAMI,OAAab,KAAK;AAO/B,MAAMc,YAAYC,OAAOC,GAAG,CAAC;AAO7B,SAASC,gBAA8CC,KAAQ;IAC7D,AAAC,IAAI,CAAkBA,KAAK,GAAGA;AACjC;AACCD,gBAAgBE,SAAS,AAA0B,CAACL,UAAU,GAAG;AAmClE,OAAO,SAASM,KAAKC,MAAe;IAClC,OAAO,CAAEA,QAAoC,CAACP,UAAU;AAC1D;AAcA,OAAO,SAASQ,MAAMD,MAAe;IACnC,OAAO,AAACA,QAAoC,CAACP,UAAU,KAAK;AAC9D;AAEA,OAAO,SAASS,YAAed,KAAQ;IACrC,OAAOA;AACT;AAUA,OAAO,SAASe,GAAMf,KAAQ;IAC5B,IAAIa,MAAMb,QAAQ;QAChB,MAAM,IAAIG,UAAU;IACtB;IACA,OAAOW,YAAYd;AACrB;AAUA,OAAO,SAASgB,IAAOP,KAAQ;IAC7B,OAAO,IAAKD,gBAAwDC;AACtE;AAUA,OAAO,SAASQ,WAAcjB,KAAsB;IAClD,OAAO,OAAQA,OAA0BkB,SAAS;AACpD;AAOA,OAAO,SAASC,OAAUnB,KAAsB;IAC9C,OAAO,OAAQA,OAA0BkB,SAAS;AACpD"}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["/** Values that represent None (absence of a value). */\nexport type NoneValueType = null | undefined | void;\n\n/** Widens literal types to their base types for better type inference. */\nexport type Widen<T> = T extends string\n ? string\n : T extends number\n ? number\n : T extends boolean\n ? boolean\n : T extends bigint\n ? bigint\n : T extends symbol\n ? symbol\n : T;\n\n/** Widens never to unknown, otherwise preserves the type. */\nexport type WidenNever<T> = [T] extends [never] ? unknown : T;\n\n/** Excludes None values from a type, leaving only valid Some values. */\nexport type ValueType<T> = Exclude<T, NoneValueType>;\n\nexport declare const SOME_BRAND: unique symbol;\n\n/** Represents a value that is present. The value itself is the Some - no wrapper object. */\nexport type Some<T> = ValueType<T> & { readonly [SOME_BRAND]: true };\n\n/** Represents the absence of a value (null or undefined). */\nexport type None = NoneValueType & { readonly [SOME_BRAND]: false };\n\nexport type UnOption<V, T extends Option<V>> = T extends Some<V> ? V : None;\n\n/** Constant representing None. Use this instead of null/undefined for clarity. */\nexport const NONE = undefined as None;\n\n/** Shared frozen empty array to avoid allocations. */\nexport const EMPTY: readonly unknown[] = Object.freeze([]);\n\n/** A value that may or may not be present. Some(T) is the value itself; None is null/undefined. */\nexport type Option<T> = Some<ValueType<T>> | None;\n\n/** Extracts the value type from an Option type. */\nexport type OptionValue<TOption> = TOption extends Option<infer TValue> ? TValue : never;\n\n/** Type predicate: true if T is an Option type. */\nexport type IsOption<T> = T extends Option<any> ? true : false;\n\n/** Infers the Some type from a value, preserving the inner type. */\nexport type InferSome<T> = T extends Some<infer TValue> ? Some<ValueType<TValue>> : never;\n\n/**\n * Checks if an Option contains a value (is Some).\n * @param opt - The Option to check\n * @returns true if the Option is Some, false if None\n * @example\n * isSome(42) // true\n * isSome(null) // false\n * isSome(undefined) // false\n */\nexport function isSome<T>(opt: Some<T>): true;\nexport function isSome(opt: None): false;\nexport function isSome<T>(opt: unknown): opt is Some<T>;\nexport function isSome(opt: unknown): boolean {\n return opt !== null && opt !== undefined;\n}\n\n/**\n * Checks if an Option is None (absent).\n * @param opt - The Option to check\n * @returns true if the Option is None, false if Some\n * @example\n * isNone(null) // true\n * isNone(undefined) // true\n * isNone(42) // false\n */\nexport function isNone<T>(opt: Some<T>): false;\nexport function isNone(opt: None): true;\nexport function isNone(opt: unknown): opt is None;\nexport function isNone(opt: unknown): boolean {\n return opt === null || opt === undefined;\n}\n\n/**\n * Creates an Option from a nullable value. Returns None for null/undefined, Some otherwise.\n * @param value - The value to wrap\n * @returns Some(value) if value is non-null, None otherwise\n * @example\n * optionOf(42) // Some(42)\n * optionOf(null) // None\n * optionOf(undefined) // None\n */\nexport function optionOf(value: null): None;\nexport function optionOf(value: undefined): None;\nexport function optionOf<T>(value: T): T extends NoneValueType ? None : Some<T>;\nexport function optionOf<T>(value: T): Option<T> {\n return isNone(value as Option<T>) ? NONE : (value as Some<T>);\n}\n\nexport function someUnchecked<T>(value: T): Some<ValueType<T>> {\n return value as Some<ValueType<T>>;\n}\n\n/**\n * Creates a Some value with runtime validation.\n * @param value - The value to wrap\n * @returns The value typed as Some\n * @throws TypeError if value is null or undefined\n * @example\n * some(42) // Some(42)\n */\nexport function some<T>(value: ValueType<T>): Some<ValueType<T>> {\n if (value === null || value === undefined) {\n throw new TypeError('some() requires a non-nullable value');\n }\n return someUnchecked(value);\n}\n\n/** Constant representing None. Alias for NONE. */\nexport const none: None = NONE;\n\ndeclare const OK_BRAND: unique symbol;\n\n/** Represents a successful Result value. The value itself is the Ok - no wrapper object. */\nexport type Ok<T> = T & { readonly [OK_BRAND]: true };\n\nconst ERR_BRAND = Symbol.for('nalloc.ResultError');\n\ninterface ResultErrorShape<E> {\n readonly error: E;\n readonly [ERR_BRAND]: true;\n}\n\nfunction ResultErrorCtor<E>(this: ResultErrorShape<E>, error: E): void {\n (this as { error: E }).error = error;\n}\n(ResultErrorCtor.prototype as { [ERR_BRAND]: true })[ERR_BRAND] = true;\n\n/** The error wrapper type used internally. */\nexport type ResultError<E> = ResultErrorShape<E>;\n\n/** Represents a failed Result containing an error. */\nexport type Err<E> = ResultError<E>;\n\n/** A value that is either successful (Ok) or failed (Err). Ok is the value itself; Err wraps the error. */\nexport type Result<T, E> = Ok<T> | Err<E>;\n\n/** Extracts the success value type from a Result type. */\nexport type ResultValue<TResult> = TResult extends Result<infer TValue, any> ? TValue : never;\n\n/** Extracts the error type from a Result type. */\nexport type ResultErrorType<TResult> = TResult extends Result<any, infer TError> ? TError : never;\n\n/** Type predicate: true if T is a Result type. */\nexport type IsResult<T> = T extends Result<any, any> ? true : false;\n\n/** Infers the Err type from a value, preserving the error type. */\nexport type InferErr<T> = T extends Err<infer TError> ? Err<TError> : never;\n\n/**\n * Checks if a Result is Ok (successful).\n * @param result - The Result to check\n * @returns true if the Result is Ok, false if Err\n * @example\n * isOk(42) // true (Ok value)\n * isOk(err('fail')) // false\n */\nexport function isOk<T>(result: Ok<T>): true;\nexport function isOk<E>(result: Err<E>): false;\nexport function isOk<T, E>(result: Result<T, E>): result is Ok<T>;\nexport function isOk(result: unknown): boolean;\nexport function isOk(result: unknown): boolean {\n return typeof result !== 'object' || result === null || !(result as Record<symbol, boolean>)[ERR_BRAND];\n}\n\n/**\n * Checks if a Result is Err (failed).\n * @param result - The Result to check\n * @returns true if the Result is Err, false if Ok\n * @example\n * isErr(err('fail')) // true\n * isErr(42) // false (Ok value)\n */\nexport function isErr<E>(result: Err<E>): true;\nexport function isErr(result: Ok<unknown>): false;\nexport function isErr<T, E>(result: Result<T, E>): result is Err<E>;\nexport function isErr(result: unknown): result is Err<unknown>;\nexport function isErr(result: unknown): boolean {\n return typeof result === 'object' && result !== null && (result as Record<symbol, boolean>)[ERR_BRAND] === true;\n}\n\nexport function okUnchecked<T>(value: T): Ok<T> {\n return value as Ok<T>;\n}\n\n/**\n * Creates an Ok value with runtime validation.\n * @param value - The success value\n * @returns The value typed as Ok\n * @throws TypeError if value is an Err\n * @example\n * ok(42) // Ok(42)\n */\nexport function ok<T>(value: T): Ok<T> {\n if (isErr(value)) {\n throw new TypeError('ok() cannot wrap an Err value');\n }\n return okUnchecked(value);\n}\n\n/**\n * Creates an Err value wrapping an error.\n * @param error - The error value\n * @returns An Err containing the error\n * @example\n * err('something went wrong') // Err('something went wrong')\n * err(new Error('failed')) // Err(Error)\n */\nexport function err<E>(error: E): Err<E> {\n return new (ResultErrorCtor as unknown as new (error: E) => Err<E>)(error);\n}\n\n/** A value that may or may not be a Promise. */\nexport type MaybePromise<T> = T | Promise<T> | PromiseLike<T>;\n\n/**\n * Checks if a value is a thenable (has a .then method).\n * @param value - The value to check\n * @returns true if value is a PromiseLike\n */\nexport function isThenable<T>(value: MaybePromise<T>): value is PromiseLike<T> {\n return (typeof value === 'object' || typeof value === 'function') && value !== null && typeof (value as PromiseLike<T>).then === 'function';\n}\n\n/**\n * Checks if a value is synchronous (not a thenable).\n * @param value - The value to check\n * @returns true if value is not a PromiseLike\n */\nexport function isSync<T>(value: MaybePromise<T>): value is T {\n return !(typeof value === 'object' || typeof value === 'function') || value === null || typeof (value as PromiseLike<T>).then !== 'function';\n}\n"],"names":["NONE","undefined","EMPTY","Object","freeze","isSome","opt","isNone","optionOf","value","someUnchecked","some","TypeError","none","ERR_BRAND","Symbol","for","ResultErrorCtor","error","prototype","isOk","result","isErr","okUnchecked","ok","err","isThenable","then","isSync"],"mappings":"AAiCA,OAAO,MAAMA,OAAOC,UAAkB;AAGtC,OAAO,MAAMC,QAA4BC,OAAOC,MAAM,CAAC,EAAE,EAAE;AA0B3D,OAAO,SAASC,OAAOC,GAAY;IACjC,OAAOA,QAAQ,QAAQA,QAAQL;AACjC;AAcA,OAAO,SAASM,OAAOD,GAAY;IACjC,OAAOA,QAAQ,QAAQA,QAAQL;AACjC;AAcA,OAAO,SAASO,SAAYC,KAAQ;IAClC,OAAOF,OAAOE,SAAsBT,OAAQS;AAC9C;AAEA,OAAO,SAASC,cAAiBD,KAAQ;IACvC,OAAOA;AACT;AAUA,OAAO,SAASE,KAAQF,KAAmB;IACzC,IAAIA,UAAU,QAAQA,UAAUR,WAAW;QACzC,MAAM,IAAIW,UAAU;IACtB;IACA,OAAOF,cAAcD;AACvB;AAGA,OAAO,MAAMI,OAAab,KAAK;AAO/B,MAAMc,YAAYC,OAAOC,GAAG,CAAC;AAO7B,SAASC,gBAA8CC,KAAQ;IAC7D,AAAC,IAAI,CAAkBA,KAAK,GAAGA;AACjC;AACCD,gBAAgBE,SAAS,AAA0B,CAACL,UAAU,GAAG;AAmClE,OAAO,SAASM,KAAKC,MAAe;IAClC,OAAO,OAAOA,WAAW,YAAYA,WAAW,QAAQ,CAAC,AAACA,MAAkC,CAACP,UAAU;AACzG;AAcA,OAAO,SAASQ,MAAMD,MAAe;IACnC,OAAO,OAAOA,WAAW,YAAYA,WAAW,QAAQ,AAACA,MAAkC,CAACP,UAAU,KAAK;AAC7G;AAEA,OAAO,SAASS,YAAed,KAAQ;IACrC,OAAOA;AACT;AAUA,OAAO,SAASe,GAAMf,KAAQ;IAC5B,IAAIa,MAAMb,QAAQ;QAChB,MAAM,IAAIG,UAAU;IACtB;IACA,OAAOW,YAAYd;AACrB;AAUA,OAAO,SAASgB,IAAOP,KAAQ;IAC7B,OAAO,IAAKD,gBAAwDC;AACtE;AAUA,OAAO,SAASQ,WAAcjB,KAAsB;IAClD,OAAO,AAAC,CAAA,OAAOA,UAAU,YAAY,OAAOA,UAAU,UAAS,KAAMA,UAAU,QAAQ,OAAO,AAACA,MAAyBkB,IAAI,KAAK;AACnI;AAOA,OAAO,SAASC,OAAUnB,KAAsB;IAC9C,OAAO,CAAE,CAAA,OAAOA,UAAU,YAAY,OAAOA,UAAU,UAAS,KAAMA,UAAU,QAAQ,OAAO,AAACA,MAAyBkB,IAAI,KAAK;AACpI"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nalloc",
3
3
  "description": "Rust-like Option and Result for TypeScript with near-zero allocations for extreme performance",
4
- "version": "0.0.2",
4
+ "version": "0.1.0",
5
5
  "type": "module",
6
6
  "types": "build/index.d.ts",
7
7
  "main": "build/index.cjs",
@@ -50,15 +50,32 @@
50
50
  "result",
51
51
  "maybe",
52
52
  "either",
53
+ "ok",
54
+ "err",
55
+ "some",
56
+ "none",
57
+ "unwrap",
53
58
  "rust",
54
59
  "typescript",
55
60
  "type-safe",
56
61
  "monad",
57
62
  "functional",
63
+ "fp",
64
+ "adt",
65
+ "algebraic-data-types",
66
+ "discriminated-union",
58
67
  "error-handling",
68
+ "try-catch",
69
+ "safe",
70
+ "nullable",
71
+ "null-safety",
59
72
  "pattern-matching",
60
73
  "zero-allocation",
61
- "performance"
74
+ "no-allocation",
75
+ "gc-friendly",
76
+ "performance",
77
+ "neverthrow-alternative",
78
+ "fp-ts-alternative"
62
79
  ],
63
80
  "author": "Ivan Zakharchanka",
64
81
  "license": "MIT",
@@ -68,23 +85,25 @@
68
85
  "homepage": "https://github.com/3axap4eHko/nalloc#readme",
69
86
  "devDependencies": {
70
87
  "@eslint/js": "^10.0.1",
71
- "@vitest/coverage-v8": "^4.0.18",
72
- "eslint": "^10.0.2",
88
+ "@vitest/coverage-v8": "^4.1.2",
89
+ "eslint": "^10.1.0",
73
90
  "eslint-plugin-prettier": "^5.5.5",
74
91
  "inop": "^0.9.0",
75
- "overtake": "^1.4.0",
92
+ "overtake": "^2.1.1",
76
93
  "prettier": "^3.8.1",
77
94
  "tsafe": "^1.8.12",
78
95
  "tslib": "^2.8.1",
79
- "typescript": "^5.9.3",
80
- "typescript-eslint": "^8.56.1",
81
- "vitest": "^4.0.18"
96
+ "typescript": "^6.0.2",
97
+ "typescript-eslint": "^8.58.0",
98
+ "vitest": "^4.1.2"
82
99
  },
83
100
  "scripts": {
84
- "check": "tsc src/__tests__/option.types.ts src/__tests__/result.types.ts --noEmit --lib esnext,dom --target esnext --module nodenext --moduleResolution nodenext",
101
+ "check": "tsc --noEmit -p tsconfig.check.json",
85
102
  "build": "rm -rf build && inop src build -i __tests__ -i *.tmp.ts && tsc --declaration --emitDeclarationOnly",
86
103
  "lint": "eslint .",
87
104
  "test": "vitest run",
88
- "bench": "overtake benchmarks/*"
105
+ "bench": "overtake benchmarks/* --pin-cores -w 2 --progress",
106
+ "bench:save": "pnpm bench --save-baseline .bench-baseline.json",
107
+ "bench:test": "pnpm bench --compare-baseline .bench-baseline.json"
89
108
  }
90
109
  }
@@ -45,7 +45,8 @@ import {
45
45
  filterOk,
46
46
  filterErr,
47
47
  safeTry,
48
- safeTryAsync
48
+ safeTryAsync,
49
+ fromPromise
49
50
  } from '../result.js';
50
51
  import { ok, err, isOk, isErr, optionOf as optOf, none } from '../types.js';
51
52
 
@@ -913,4 +914,39 @@ describe('Result', () => {
913
914
  });
914
915
  });
915
916
 
917
+ describe('fromPromise', () => {
918
+ it('returns Ok for resolved promise', async () => {
919
+ const result = await fromPromise(Promise.resolve(42));
920
+ expect(isOk(result)).toBe(true);
921
+ expect(result).toBe(42);
922
+ });
923
+
924
+ it('returns Err for rejected promise', async () => {
925
+ const result = await fromPromise(Promise.reject(new Error('boom')));
926
+ expect(isErr(result)).toBe(true);
927
+ expect((result as { error: Error }).error.message).toBe('boom');
928
+ });
929
+
930
+ it('uses onError mapper for rejected promise', async () => {
931
+ const result = await fromPromise(
932
+ Promise.reject(new Error('boom')),
933
+ (e) => `mapped: ${(e as Error).message}`,
934
+ );
935
+ expect(isErr(result)).toBe(true);
936
+ expect((result as { error: string }).error).toBe('mapped: boom');
937
+ });
938
+
939
+ it('handles Ok(null) as valid success', async () => {
940
+ const result = await fromPromise(Promise.resolve(null));
941
+ expect(isOk(result)).toBe(true);
942
+ expect(result).toBe(null);
943
+ });
944
+
945
+ it('returns Err with unknown type when no onError provided', async () => {
946
+ const result = await fromPromise(Promise.reject('string error'));
947
+ expect(isErr(result)).toBe(true);
948
+ expect((result as { error: string }).error).toBe('string error');
949
+ });
950
+ });
951
+
916
952
  });
@@ -207,7 +207,7 @@ assert<Equals<typeof tryCatchTyped, Result<number, string>>>;
207
207
 
208
208
 
209
209
  const unwrapFallback = unwrapOrReturn(ok(1) as Result<number, string>, () => 'fallback');
210
- assert<Equals<typeof unwrapFallback, number | string>>;
210
+ assert<Equals<typeof unwrapFallback, number | 'fallback'>>;
211
211
 
212
212
  declare const maybeResult: Result<number, string>;
213
213
  assertOk(maybeResult);
package/src/option.ts CHANGED
@@ -158,11 +158,7 @@ export function flatMap<T, U>(opt: Option<T>, fn: (value: T) => Option<U>): Opti
158
158
  * @param fn - Function returning an Option
159
159
  * @returns The result of fn(value) if Some, None otherwise
160
160
  */
161
- export function andThen<T, U>(opt: None, fn: (value: T) => Option<U>): None;
162
- export function andThen<T, U>(opt: Option<T>, fn: (value: T) => Option<U>): Option<U>;
163
- export function andThen<T, U>(opt: Option<T>, fn: (value: T) => Option<U>): Option<U> {
164
- return isNone(opt) ? NONE : fn(opt);
165
- }
161
+ export const andThen: typeof flatMap = flatMap;
166
162
 
167
163
  /**
168
164
  * Executes a side effect if Some, then returns the original Option.
@@ -312,8 +308,9 @@ export function orElse<T>(opt: Option<T>, fn: () => Option<T>): Option<T> {
312
308
  * xor(none, none) // None
313
309
  */
314
310
  export function xor<T>(opt: Option<T>, optb: Option<T>): Option<T> {
315
- if (isSome(opt) && isNone(optb)) return opt;
316
- if (isNone(opt) && isSome(optb)) return optb;
311
+ const a = isSome(opt);
312
+ const b = isSome(optb);
313
+ if (a !== b) return a ? opt : optb;
317
314
  return NONE;
318
315
  }
319
316
 
@@ -411,7 +408,7 @@ export function flatten<T>(opt: Option<Option<T>>): Option<T> {
411
408
  * contains(none, 42) // false
412
409
  */
413
410
  export function contains<T>(opt: Option<T>, value: T): boolean {
414
- return isSome(opt) && opt === value;
411
+ return isSome(opt) && (opt === value || (opt !== opt && value !== value));
415
412
  }
416
413
 
417
414
  /**
package/src/result.ts CHANGED
@@ -33,6 +33,25 @@ export function of<T>(fn: () => T): Result<T, unknown> {
33
33
  return tryCatch(fn);
34
34
  }
35
35
 
36
+ /**
37
+ * Converts a Promise to a Result. Resolves to Ok if successful, Err on rejection.
38
+ * @param promise - The promise to convert
39
+ * @param onError - Optional error transformer
40
+ * @returns Promise resolving to Ok(value) or Err(error)
41
+ * @example
42
+ * await fromPromise(fetch('/api')) // Ok(Response) or Err(unknown)
43
+ * await fromPromise(fetch('/api'), e => String(e)) // Ok(Response) or Err(string)
44
+ */
45
+ export async function fromPromise<T>(promise: Promise<T>): Promise<Result<T, unknown>>;
46
+ export async function fromPromise<T, E>(promise: Promise<T>, onError: (error: unknown) => E): Promise<Result<T, E>>;
47
+ export async function fromPromise<T, E = unknown>(promise: Promise<T>, onError?: (error: unknown) => E): Promise<Result<T, E>> {
48
+ try {
49
+ return (await promise) as Ok<T>;
50
+ } catch (error) {
51
+ return ERR(onError ? onError(error) : (error as E));
52
+ }
53
+ }
54
+
36
55
  /**
37
56
  * Executes a function that may return sync or async, preserving sync execution when possible.
38
57
  * @param fn - Function that may return T or Promise<T>
@@ -99,7 +118,7 @@ export function assertOk<T, E>(result: Result<T, E>, message?: string): asserts
99
118
  */
100
119
  export function assertErr<T, E>(result: Result<T, E>, message?: string): asserts result is Err<E> {
101
120
  if (isOk(result)) {
102
- throw new Error(message ?? 'Expected Err result.');
121
+ throw new Error(message ?? `Expected Err result. Received value: ${String(result)}`);
103
122
  }
104
123
  }
105
124
 
@@ -169,11 +188,7 @@ export function flatMap<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<
169
188
  * @param fn - Function returning a Result
170
189
  * @returns The result of fn(value) if Ok, Err unchanged
171
190
  */
172
- export function andThen<T, U, E>(result: Err<E>, fn: (value: T) => Result<U, E>): Err<E>;
173
- export function andThen<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E>;
174
- export function andThen<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E> {
175
- return isErr(result) ? result : fn(result);
176
- }
191
+ export const andThen: typeof flatMap = flatMap;
177
192
 
178
193
  /**
179
194
  * Executes a side effect if Ok, then returns the original Result.
@@ -532,11 +547,13 @@ export function filterErr<T, E>(results: Iterable<Result<T, E>>): E[] {
532
547
  * collect([ok(1), err('e')]) // Err('e')
533
548
  */
534
549
  export function collect<T, E>(results: Result<T, E>[]): Result<T[], E> {
535
- const values: T[] = [];
550
+ const len = results.length;
551
+ const values = new Array<T>(len);
536
552
 
537
- for (const result of results) {
553
+ for (let i = 0; i < len; i++) {
554
+ const result = results[i];
538
555
  if (isErr(result)) return result;
539
- values.push(result);
556
+ values[i] = result;
540
557
  }
541
558
 
542
559
  return values as Ok<T[]>;
@@ -551,7 +568,15 @@ export function collect<T, E>(results: Result<T, E>[]): Result<T[], E> {
551
568
  * collectAll([ok(1), err('a'), err('b')]) // Err(['a', 'b'])
552
569
  */
553
570
  export function collectAll<T, E>(results: Result<T, E>[]): Result<T[], E[]> {
554
- const [oks, errs] = partition(results);
571
+ const oks: T[] = [];
572
+ const errs: E[] = [];
573
+ for (const result of results) {
574
+ if (isOk(result)) {
575
+ oks.push(result);
576
+ } else {
577
+ errs.push(result.error);
578
+ }
579
+ }
555
580
  return errs.length > 0 ? ERR(errs) : (oks as Ok<T[]>);
556
581
  }
557
582
 
@@ -688,25 +713,38 @@ export async function partitionMaybePromiseAsync<T, E>(
688
713
  startIndex: number = 0,
689
714
  ): Promise<[Widen<T>[], WidenNever<E>[]]> {
690
715
  const suffixLength = values.length - startIndex;
691
- const pending = new Array<Promise<Result<T, E>>>(suffixLength);
716
+ const pendingPromises: Promise<Result<T, E>>[] = [];
692
717
 
693
718
  for (let i = 0; i < suffixLength; i++) {
694
719
  const value = values[startIndex + i];
695
- pending[i] = Promise.resolve(value).then(
696
- (result) => result as Result<T, E>,
697
- (error) => ERR(error as E),
698
- );
720
+ if (isThenable(value)) {
721
+ pendingPromises.push(
722
+ Promise.resolve(value).then(
723
+ (result) => result as Result<T, E>,
724
+ (error) => ERR(error as E),
725
+ ),
726
+ );
727
+ } else {
728
+ if (isOk(value)) {
729
+ oks.push(value as Widen<T>);
730
+ } else {
731
+ errs.push((value as Err<WidenNever<E>>).error);
732
+ }
733
+ }
699
734
  }
700
735
 
701
- const resolved = await Promise.all(pending);
702
- for (let i = 0; i < resolved.length; i++) {
703
- const result = resolved[i];
704
- if (isOk(result)) {
705
- oks.push(result as Widen<T>);
706
- } else {
707
- errs.push((result as Err<WidenNever<E>>).error);
736
+ if (pendingPromises.length > 0) {
737
+ const resolved = await Promise.all(pendingPromises);
738
+ for (let i = 0; i < resolved.length; i++) {
739
+ const result = resolved[i];
740
+ if (isOk(result)) {
741
+ oks.push(result as Widen<T>);
742
+ } else {
743
+ errs.push((result as Err<WidenNever<E>>).error);
744
+ }
708
745
  }
709
746
  }
747
+
710
748
  return [oks, errs] as [Widen<T>[], WidenNever<E>[]];
711
749
  }
712
750
 
package/src/types.ts CHANGED
@@ -28,6 +28,8 @@ export type Some<T> = ValueType<T> & { readonly [SOME_BRAND]: true };
28
28
  /** Represents the absence of a value (null or undefined). */
29
29
  export type None = NoneValueType & { readonly [SOME_BRAND]: false };
30
30
 
31
+ export type UnOption<V, T extends Option<V>> = T extends Some<V> ? V : None;
32
+
31
33
  /** Constant representing None. Use this instead of null/undefined for clarity. */
32
34
  export const NONE = undefined as None;
33
35
 
@@ -167,7 +169,7 @@ export function isOk<E>(result: Err<E>): false;
167
169
  export function isOk<T, E>(result: Result<T, E>): result is Ok<T>;
168
170
  export function isOk(result: unknown): boolean;
169
171
  export function isOk(result: unknown): boolean {
170
- return !(result as Record<symbol, unknown>)?.[ERR_BRAND];
172
+ return typeof result !== 'object' || result === null || !(result as Record<symbol, boolean>)[ERR_BRAND];
171
173
  }
172
174
 
173
175
  /**
@@ -183,7 +185,7 @@ export function isErr(result: Ok<unknown>): false;
183
185
  export function isErr<T, E>(result: Result<T, E>): result is Err<E>;
184
186
  export function isErr(result: unknown): result is Err<unknown>;
185
187
  export function isErr(result: unknown): boolean {
186
- return (result as Record<symbol, unknown>)?.[ERR_BRAND] === true;
188
+ return typeof result === 'object' && result !== null && (result as Record<symbol, boolean>)[ERR_BRAND] === true;
187
189
  }
188
190
 
189
191
  export function okUnchecked<T>(value: T): Ok<T> {
@@ -226,7 +228,7 @@ export type MaybePromise<T> = T | Promise<T> | PromiseLike<T>;
226
228
  * @returns true if value is a PromiseLike
227
229
  */
228
230
  export function isThenable<T>(value: MaybePromise<T>): value is PromiseLike<T> {
229
- return typeof (value as PromiseLike<T>)?.then === 'function';
231
+ return (typeof value === 'object' || typeof value === 'function') && value !== null && typeof (value as PromiseLike<T>).then === 'function';
230
232
  }
231
233
 
232
234
  /**
@@ -235,5 +237,5 @@ export function isThenable<T>(value: MaybePromise<T>): value is PromiseLike<T> {
235
237
  * @returns true if value is not a PromiseLike
236
238
  */
237
239
  export function isSync<T>(value: MaybePromise<T>): value is T {
238
- return typeof (value as PromiseLike<T>)?.then !== 'function';
240
+ return !(typeof value === 'object' || typeof value === 'function') || value === null || typeof (value as PromiseLike<T>).then !== 'function';
239
241
  }