typescript - Typ för en enhet med valfria hämtbara relationer
Jag har ett REST-API som valfritt kan hämta relationer, om jag ber det att göra det: till exempel, om jag anropar GET /payment-request får jag denna payload (förenklad för tydlighetens skull):
[
{
"id": "01FBPR3K0RYBCRGCBWEC2AK30P",
"payer": "01FBRKNQRP74VBWW67N4BTH40B",
"payee": "01FB460C0FC6BSTK835VF5735J",
"dueDate": "2021-07-31",
"amount": 99988
}
]
Men om jag anropar GET /payment-request?fetch=payee får jag
[
{
"id": "01FBPR3K0RYBCRGCBWEC2AK30P",
"payer": "01FBRKNQRP74VBWW67N4BTH40B",
"payee": {
"id": "01FB460C0FC6BSTK835VF5735J",
"fullName": "John Doe",
"email": "[email "
},
"dueDate": "2021-07-31",
"amount": 99988
}
]
Jag kan också hämta flera relationer samtidigt, som GET /payment-request?fetch=payer,payee. Både payer och payee är inte nullbara, men jag har också andra enheter som har mer flexibla begränsningar. I princip kan varje relation vara nullbar och kan peka på en annan typ.
För tillfället är de typer som jag använder på frontend ganska enkla, men det känns ganska klumpigt och jag behöver göra ett antal typkontroller i min kod:
type BusinessEntity = {
id: string;
fullName: string;
email: string;
};
type PaymentRequest = {
id: string;
payer: string | BusinessEntity;
payee: string | BusinessEntity;
dueDate: string;
amount: number;
};
Idag har jag försökt ta fram någon form av generisk för att beskriva valfria hämtningar, men det fungerar bara med en enskild obligatorisk hämtning:
type PaymentRequest<Fetched extends ('payer' | 'payee')[]> = {
id: string;
payer: Fetched extends ['payer'] ? BusinessEntity : string;
payee: Fetched extends ['payee'] ? BusinessEntity : string;
dueDate: string;
amount: number;
};
På det här sättet kan jag göra något, men inte allt:
let plain : PaymentRequest<[]>; // OK: both payed and payee are string
let single : PaymentRequest<['payer']>; // OK: payer is a BusinessEntity, payee is a string
let double : PaymentRequest<['payer', 'payee']>; // WRONG: both payer and payee are string again
Jag har ingen aning om hur man kollar om en "array generic type" innehåller ett enda värde. Har någon ett råd till mig?
Den slutgiltiga lösningen
Jag har tagit kapten Yossarians lösning och jag har arbetat lite vidare för att förenkla den:
type PaymentRequest<Fetched extends 'payer'|'payee'|''=''> = {
id: string;
payer: 'payer' extends Fetched ? BusinessEntity : string;
payee: 'payee' extends Fetched ? BusinessEntity : string;
dueDate: string;
amount: number;
};
Nu är syntaxen mer koncis, och jag kan bara ignorera generiken när jag hanterar standardoutputen:
let plain : PaymentRequest; // OK: both payed and payee are string
let single : PaymentRequest<'payer'>; // OK: payer is a BusinessEntity, payee is a string
let double : PaymentRequest<'payer'|'payee'>; // OK: both payer and payee are BusinessEntity
Svar #1
Letar du efter något liknande detta?
type BusinessEntity = {
id: string;
fullName: string;
email: string;
};
type CustomPaymentRequest<Fetched extends ('payer' | 'payee')[]> = {
id: string;
payer: 'payer' extends Fetched[number] ? BusinessEntity : string;
payee: 'payee' extends Fetched[number] ? BusinessEntity : string;
dueDate: string;
amount: number;
};
let plain: CustomPaymentRequest<[]>;
let single: CustomPaymentRequest<['payer']>;
let double: CustomPaymentRequest<['payer', 'payee']>;
type O = CustomPaymentRequest<['payer']>['payee'] // string
type OO = CustomPaymentRequest<['payee']>['payee'] // BusinessEntity
Lekplats
