-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
52 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'>; |