Utilizing my REST API allows me the option to fetch relations based on specific requests. For instance, a basic call like GET /payment-request
will return the following simplified payload:
[
{
"id": "01FBPR3K0RYBCRGCBWEC2AK30P",
"payer": "01FBRKNQRP74VBWW67N4BTH40B",
"payee": "01FB460C0FC6BSTK835VF5735J",
"dueDate": "2021-07-31",
"amount": 99988
}
]
However, by adding a parameter like ?fetch=payee
to the request, the response will include additional details as shown below:
[
{
"id": "01FBPR3K0RYBCRGCBWEC2AK30P",
"payer": "01FBRKNQRP74VBWW67N4BTH40B",
"payee": {
"id": "01FB460C0FC6BSTK835VF5735J",
"fullName": "John Doe",
"email": "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="1973767177596d7c6a6d377a7674">[email protected]</a>"
},
"dueDate": "2021-07-31",
"amount": 99988
}
]
The ability to fetch multiple relations simultaneously is also supported, for example:
GET /payment-request?fetch=payer,payee
. While payer
and payee
are mandatory, there are other entities with more flexible constraints which can be nullable or point to different types.
Currently, my frontend data types are straightforward but require numerous type checks in the code:
type BusinessEntity = {
id: string;
fullName: string;
email: string;
};
type PaymentRequest = {
id: string;
payer: string | BusinessEntity;
payee: string | BusinessEntity;
dueDate: string;
amount: number;
};
In attempting to create a generic description for optional fetches, I encountered limitations when multiple fetches were requested:
type PaymentRequest<Fetched extends ('payer' | 'payee')[]> = {
id: string;
payer: Fetched extends ['payer'] ? BusinessEntity : string;
payee: Fetched extends ['payee'] ? BusinessEntity : string;
dueDate: string;
amount: number;
};
While this approach worked for single fetches, it struggled with multiples as illustrated in the examples provided.
If anyone has suggestions on how to verify if an "array generic type" contains only one value, please share your insights!
Final Solution
Building upon captain-yossarian's solution, I have refined it further for enhanced simplicity:
type PaymentRequest<Fetched extends 'payer'|'payee'|''=''> = {
id: string;
payer: 'payer' extends Fetched ? BusinessEntity : string;
payee: 'payee' extends Fetched ? BusinessEntity : string;
dueDate: string;
amount: number;
};
This revised syntax offers a more concise structure, allowing for seamless handling of standard outputs without needing to specify the generic every time:
let plain : PaymentRequest; // OK: both payer and payee are strings
let single : PaymentRequest<'payer'>; // OK: payer is a BusinessEntity, payee is a string
let double : PaymentRequest<'payer'|'payee'>; // OK: both payer and payee are BusinessEntities