Untyped hook payloads — parameters typed as any, unknown, or Record<string, any> — eliminate compile-time safety from every plugin in the ecosystem. Plugin authors get no autocompletion, no error on typos in property names, and no signal when a host update renames a payload field. Breakage appears only at runtime, often in production. ISO 25010 maintainability.analysability scores fall sharply when the API surface cannot be understood without running code; typed payloads are the primary mechanism for making plugin APIs analysable.
High because untyped hook payloads remove compile-time safety from the entire plugin ecosystem, causing payload-shape mismatches to surface only as runtime errors in plugin authors' production deployments.
Define a typed map of all hook payloads and use generic registration to infer types at call sites. This converts payload shape errors from runtime crashes into compile-time failures, and provides IDE autocompletion to every plugin author.
interface HookPayloads {
'before:request': { request: Request; config: PluginConfig };
'after:response': { request: Request; response: Response; duration: number };
'on:error': { error: Error; request: Request; retryCount: number };
}
on<K extends keyof HookPayloads>(
hook: K,
handler: (payload: HookPayloads[K]) => void | Promise<void>
): void;
ID: plugin-extension-architecture.hook-system.type-safety
Severity: high
What to look for: Check whether hook handler parameters (the "payload" or "context" passed to each handler) are typed with TypeScript interfaces, generics, or JSDoc annotations. Look for:
interface BeforeRequestContext { url: string; headers: Headers })hooks.on<BeforeRequest>('before:request', (ctx) => { /* ctx is typed */ })@param annotations on hook invocations if not using TypeScript
Without typed payloads, plugin authors must read host source code to understand what data their handlers receive, which is the top cause of broken plugins after host updates.Pass criteria: Count all plugin API surface types. Hook payloads are typed — either via TypeScript interfaces/generics, JSDoc annotations, or JSON Schema definitions. Plugin authors get autocompletion and compile-time errors when accessing payload properties. At minimum, the most commonly used hooks have typed payloads. At least 90% of plugin API methods must have TypeScript type definitions. Report the count of typed vs untyped API surface methods even on pass.
Fail criteria: Quote the untyped API methods or missing type definitions found. Hook payloads are any, unknown, or untyped objects. Plugin authors receive no type information about what properties are available on the context/payload object. OR payloads are typed as a loose Record<string, any> that provides no useful type narrowing.
Skip (N/A) when: The project does not use TypeScript and has no type system. Also skip for Python projects that don't use type hints, Go projects (strongly typed by default), and Rust projects (strongly typed by default).
Detail on fail: "Hook handlers receive a context parameter typed as 'any'. Plugin authors get no autocompletion, no compile-time errors for typos, and no documentation of available properties. The BeforeRequest hook passes {request, response, config} but this is only discoverable by reading the host's invokeHook() source code."
Remediation: Typed hook payloads are the most impactful improvement for plugin developer experience. They enable autocompletion, catch errors at compile time, and serve as inline documentation.
// Define payload types per hook:
interface HookPayloads {
'before:request': { request: Request; config: PluginConfig };
'after:response': { request: Request; response: Response; duration: number };
'on:error': { error: Error; request: Request; retryCount: number };
}
// Generic registration infers types:
on<K extends keyof HookPayloads>(
hook: K,
handler: (payload: HookPayloads[K]) => void | Promise<void>
): void;