@bajtos suggested to provide strongly typed context types based on the hook name.
For example:
export interface AccessHookContext<T extends typeof PersistedModel> {
Model: T;
query: Filter<T>;
}
export type Listener<Ctx> = (ctx: Ctx, next: (err?: any) => void) => void;
class PersistedModel {
// ...
static observe(operation: 'access', handler: Listener<AccessHookContext>): void;
static observe(operation: 'before save', handler: Listener<BeforeSaveHookContext>): void;
// etc.
}