Use createParamDecorator — it takes a factory receiving (data, ctx) where data is any argument passed to the decorator and ctx is the ExecutionContext. The factory extracts and returns the value to be injected. Custom param decorators can be combined with pipes for validation.
data is the argument passed at the call site: @CurrentUser('email') gives data = 'email'.
ctx is the full ExecutionContext — use switchToHttp(), switchToWs() etc. as needed.
The factory return value is what gets injected into the handler parameter.
Pipes can be passed as additional arguments or via @UsePipes() on the method.
Custom param decorators work on any transport — HTTP, WebSocket, RPC.