Reputation: 5279
When I see following code,
https://github.com/nestjs/nest/tree/master/packages/common
For example ArgumentsHost
was defined by interface.
But it seems the contents of methods are not defined.
* @publicApi
*/
export interface ArgumentsHost {
/**
* Returns the array of arguments being passed to the handler.
*/
getArgs<T extends Array<any> = any[]>(): T;
/**
* Returns a particular argument by index.
* @param index index of argument to retrieve
*/
getArgByIndex<T = any>(index: number): T;
/**
* Switch context to RPC.
* @returns interface with methods to retrieve RPC arguments
*/
switchToRpc(): RpcArgumentsHost;
/**
* Switch context to HTTP.
* @returns interface with methods to retrieve HTTP arguments
*/
switchToHttp(): HttpArgumentsHost;
/**
* Switch context to WebSockets.
* @returns interface with methods to retrieve WebSockets arguments
*/
switchToWs(): WsArgumentsHost;
/**
* Returns the current execution context type (string)
*/
getType<TContext extends string = ContextType>(): TContext;
}
But when I see following instruction,
https://docs.nestjs.com/exception-filters
ArgumentsHost
was used and switchToHttp()
works well.
Why these methods work without specific definitions ?
Do I miss big issue ? As I am beginner, if someone has opinion, please let me know.
Thanks
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception.getStatus();
response
.status(status)
.json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
Upvotes: 0
Views: 941
Reputation: 589
This is actually not specific to Nest, but to TypeScript (and other languages) in general.
The interface defines a type, and your catch
method specifies that its second argument must be some value that has that type.
What this means is that any value that has the right "shape" can be used as the second argument.
It turns out that the Nest library itself is responsible for providing a value to your defined catch
method, and when it does, it must provide a concrete "instance" of the ArgumentsHost
interface.
As an example of such an instance, see the definition of ExecutionContextHost
.
(as it turns out, ExecutionContextHost
actually implements a different interface, ExecutionContext
, but ExecutionContext
extends ArgumentsHost
, so it is a valid instance).
This is a very general and powerful technique for writing functions that only require that their inputs have a certain "shape", that is, certain properties or methods.
As an example, imagine writing a graphics library with a render
function that takes an array of objects representing shapes as input and draws them to the screen.
What type should these shapes have?
We probably want to allow for many kinds of shapes (like squares, circles, or even more exotic things), and these shapes might be very different.
However, as long as each shape knows how to draw itself, then we can write our render
function like this:
function render(shapes: Drawable[]) {
shapes.forEach(shape => shape.draw());
}
interface Drawable {
draw: () => void;
}
As a result, any object that has a suitable draw
method can be passed as part of the array of arguments to render
, regardless of whatever else it contains.
To return to your question, the draw
method isn't defined by the Drawable
interface; instead, the Drawable
interface is a way of constraining other types: it's like a kind of sieve that only allows certain things through.
The draw
method is defined by concrete instances of the interface.
For example:
class Square extends Drawable {
public x: number;
public y: number;
public sideLength: number;
draw() {
// Drawing logic here
}
}
Upvotes: 3