can1357/oh-my-pi · error · OmpTypeError

generic declarations require at least one parameter

Error message

generic declarations require at least one parameter

What it means

validateGenericParameters() requires at least one generic parameter; an empty declaration throws OmpTypeError. A generic with zero parameters has nothing to instantiate, so it's a usage mistake of the generic() API.

Source

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

export interface GenericArguments {
	readonly [name: string]: BaseType;
}

export interface GenericBuilder {
	(definition: (arguments_: GenericArguments) => unknown, hkt?: unknown): Generic;
	(definition: unknown, hkt?: unknown): Generic;
}

function validateGenericParameters(parameters: readonly GenericParameter[]): void {
	const names = new Set<string>();
	for (const parameter of parameters) {
		if (!/^[A-Za-z_$]\w*$/.test(parameter.name)) {
			throw new OmpTypeError(`invalid generic parameter "${parameter.name}"`);
		}
		if (names.has(parameter.name)) throw new OmpTypeError(`duplicate generic parameter "${parameter.name}"`);
		names.add(parameter.name);
	}
	if (parameters.length === 0) throw new OmpTypeError("generic declarations require at least one parameter");
}

function parseGenericParameters(source: string): GenericParameter[] {
	const trimmed = source.trim();
	const body = trimmed.startsWith("<") && trimmed.endsWith(">") ? trimmed.slice(1, -1) : trimmed;
	const parts: string[] = [];
	let start = 0;
	let depth = 0;
	let quote = "";
	for (let index = 0; index < body.length; index++) {
		const char = body[index];
		if (quote !== "") {
			if (char === quote && body[index - 1] !== "\\") quote = "";
			continue;
		}
		if (char === "'" || char === '"' || char === "`") quote = char;
		else if (char === "<" || char === "(" || char === "[") depth++;
		else if (char === ">" || char === ")" || char === "]") depth = Math.max(0, depth - 1);

View on GitHub (pinned to 9690622007)

Solutions

  1. Provide at least one parameter: generic('<T>', 'T[]')
  2. If the type has no type variables, drop generic() and declare it directly with type()
  3. Fix the codegen/template so it only emits generic() when at least one parameter exists
  4. Check argument order — ensure you didn't pass the body where the parameter declaration belongs

Example fix

// before
const T = generic('', 'string[]'); // throws
// after
const T = type('string[]'); // no generics needed
const G = generic('<T>', 'T[]'); // or a real generic
Defensive patterns

Strategy: validation

Validate before calling

function assertNonEmptyGenericDecl(decl: string) {
  const inner = decl.trim().replace(/^<|>$/g, '').trim();
  if (!inner) throw new Error('generic declaration needs at least one parameter');
}

Try / catch

try {
  const G = generic(decl, body);
} catch (err) {
  if (err instanceof OmpTypeError && err.message === 'generic declarations require at least one parameter') {
    throw new Error(`"${decl}" declares no parameters — use type() instead of generic()`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling generic('', '...') or generic('<>', '...') — the parser strips angle brackets, produces zero parts, and the length===0 check fires. Also happens when a dynamically built parameter list string ends up empty.

Common situations: Template-driven codegen emitting an empty parameter list when no type variables were collected; refactoring away the only parameter but keeping the generic wrapper; accidentally passing the body as the parameter argument.

Related errors


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