Skip to content

Commit

Permalink
feat: update response dto
Browse files Browse the repository at this point in the history
  • Loading branch information
gipo355 committed Jun 14, 2024
1 parent 72b90c6 commit b472d71
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 30 deletions.
5 changes: 5 additions & 0 deletions .changeset/chilled-parrots-complain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@gipo355/nest-utils': patch
---

update response dto to provide more cases and type safety
77 changes: 47 additions & 30 deletions packages/nest-utils/src/lib/dtos/response.dto.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,77 @@
import type { HttpStatus } from '@nestjs/common';
import type { Static } from '@sinclair/typebox';

/**
* IBaseResponse is a generic interface that defines the structure of the response object.
* Provides a common structure for all responses.
* Being an interface, it can be extended with another interface simply by shadowing it.
* @description
* IBaseResponse is the base interface that defines the structure of a response object.
*/
export interface IBaseResponse<T> {
export interface IBaseResponse<T = never> {
// data?: T;
// data?: T extends never ? T : Record<string, T>;
/**
* If T is never, data is undefined.
* The data to be encapsulated in the response object.
*/
data?: T;
data?: T extends never ? undefined : T;
/**
* The length of the data array.
* Optional length of the data field.
*/
length?: number;
/**
* Optional message to be sent in the response object.
* Optional message field.
*/
message?: string;
/**
* Utility key to determine if the request was successful.
* Required ok field.
*/
ok: boolean;
/**
* The status code of the response. Uses NestJS HttpStatus enum.
* Optional status code field. Based on the HttpStatus enum from NestJs.
*/
statusCode?: HttpStatus;
}
export type BaseResponseDto = Static<typeof BaseResponseDtoSchema>;

/**
* WithRequired is a utility type that makes the specified keys required for a given type or interface.
* @description
* Utility type that makes the provided keys required in the object.
*/
export type WithRequired<T, K extends keyof T> = Omit<T, K> &
Required<Pick<T, K>>;

/**
* TResponseDto is a generic type that defines the structure of the response object.
* Allows to specify the type of the data and the required keys that the response object can have.
* This way, it provides a common structure for all responses with the flexibility to add more keys or make them required to provide type safety for tests.
* Being a type, it can be extended with an union type to add more required keys.
* @param T - The type of the data to be encapsulated in the response object.
* @param L - The union type of the required keys that the response object can have. Default is standard IBaseResponse<T>.
* @description
* TResponseDto is a generic type that takes two optional parameters, T and L.
* It returns a response object based on the provided parameters.
* It's useful for creating standardized response objects with type safety for tests and consistency.
*
* @example
* TResponseDto<{user: UserDto}, 'message'> - Response object with a message key.
* Provides:
* {
* ok: boolean,
* length?: number,
* message: string,
* data: {user: UserDto},
* }
* ## T:
* - If T is not provided and L is not provided, it defaults to undefined and data field is not required.
* e.g. `TResponseDto -> { ok: boolean; }`
*
* - If T is provided and L is not provided, data field is required.
* e.g. `TResponseDto<User> -> { ok: boolean; data: User; }`
* ## L, default 'ok':
* - If T is provided, L is provided and is a key of IBaseResponse, data field is required and L is required.
* e.g. `TResponseDto<User, 'message'> -> { ok: boolean; data: User; message: string; }`
*
* - If T is not provided, L is provided and is a key of IBaseResponse, data field is not required and L is required.
* e.g. `TResponseDto<undefined, 'message'> -> { ok: boolean; message: string; }`
*
* - L can be an union of keys of IBaseResponse.
* e.g. `TResponseDto<User, 'message' | 'length'> -> { ok: boolean; data: User; message: string; length: number; }`
*
* @param T - The type of the data field in the response object. If provided makes the data field required.
* @param L - The key of the response object that should be required. Can be an union. If provided makes the keys required.
*/
export type TResponseDto<
T,
L extends keyof IBaseResponse<T> = never,
> = L extends never ? IBaseResponse<T> : WithRequired<IBaseResponse<T>, L>;
/**
* The type of the data field in the response object. If provided makes the data field required.
*/
T = undefined,
/**
* The key of the response object that should be required. Can be an union. If provided makes the keys required.
*/
L extends keyof IBaseResponse<T> = 'ok',
> = T extends undefined
? WithRequired<IBaseResponse, L>
: WithRequired<IBaseResponse<T>, L | 'data'>;

0 comments on commit b472d71

Please sign in to comment.