can1357/oh-my-pi · error · OmpTypeError

type.fn requires a function implementation

Error message

type.fn requires a function implementation

What it means

`type.fn(...)` returns a builder that must be invoked with an actual function implementation to produce the validated/typed function. Passing anything that is not a function (undefined, an object, a string) makes wrapping impossible, so omptype throws.

Source

Thrown at packages/omptype/src/type.ts:3135

			const preceding = definitions.slice(0, spreadIndexes[0]);
			if (
				preceding.some(element => typeof element === "string" && (element.endsWith("?") || /\s=\s/.test(element)))
			) {
				throw new OmpTypeError("A postfix required element cannot follow an optional or defaultable element");
			}
		}
		const parameterDefinitions = (marker === -1 ? definitions : definitions.slice(0, marker)).map(
			normalizeFnParameter,
		);
		const params = makeType<readonly unknown[], readonly unknown[]>(parseDef(parameterDefinitions, resolve), [], {});
		const returns =
			marker === -1
				? makeType<unknown>({ k: "unknown" }, [], {})
				: makeType<unknown>(parseDef(definitions[marker + 1], resolve), [], {});
		const parameterExpression = fnExpression(params.ir);
		const returnsExpression = fnExpression(returns.ir);
		return (implementation: (...arguments_: readonly unknown[]) => unknown) => {
			if (typeof implementation !== "function") throw new OmpTypeError("type.fn requires a function implementation");
			const raw = (...arguments_: readonly unknown[]): unknown => {
				const validatedArguments = params.assert(arguments_);
				const result = Reflect.apply(implementation, undefined, validatedArguments);
				return returns.assert(result);
			};
			const typed = raw.bind(undefined) as TypedFunction<readonly unknown[], unknown>;
			Object.defineProperties(typed, {
				name: { value: `bound typed ${implementation.name}`, configurable: true },
				raw: { value: implementation, enumerable: true },
				params: { value: params, enumerable: true },
				returns: { value: returns, enumerable: true },
				expression: {
					value: `(${parameterExpression.slice(1, -1)}) => ${returnsExpression}`,
					enumerable: true,
				},
			});
			return typed;
		};

View on GitHub (pinned to 9690622007)

Solutions

  1. Pass a real function to the builder returned by `type.fn`: `const f = type.fn(["string"], "number")(s => s.length)`.
  2. Check for typos/undefined variables in the implementation argument.
  3. Ensure the implementation is defined before the `type.fn` call executes (no hoisting assumptions on const arrow functions).

Example fix

// before
const parse = type.fn(["string"], "number"); // never given an implementation
// after
const parse = type.fn(["string"], "number")(s => s.length);
Defensive patterns

Strategy: validation

Validate before calling

const impl = getImplementation(); if (typeof impl !== 'function') throw new Error('implementation required'); const safeFn = type.fn(['string'], 'number')(impl);

Type guard

const isFn = (v: unknown): v is (...a: readonly unknown[]) => unknown => typeof v === 'function';

Try / catch

try { const f = type.fn(params, returns)(impl); } catch (e) { if (e instanceof OmpTypeError) reportMissingImplementation(); else throw e; }

Prevention

When it happens

Trigger: Calling the result of `type.fn(params, returns)` with a non-function value, e.g. `type.fn(["string"], "number")(undefined)`, or forgetting the final call entirely (the builder itself is passed around as the implementation).

Common situations: Destructuring that loses the implementation, conditionally assigning an implementation that ends up undefined, or calling `.fn(...)` in a curry chain and assuming validation happens without the implementation call.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/5daba246e1eb440a. Report an issue: GitHub.