ParsedAuthorizationResponse
isn't a class (which is why new
doesn't work), it's a type. In this case, it's a bunch of different possible object shapes. Let's have a look
export type ParsedAuthorizationResponse =
| IAuthResponse<
{ processorTransactionId: string },
'AUTHORIZED' | 'CANCELLED' | 'SETTLING' | 'SETTLED'
>
| IAuthResponse<{ declineReason: string }, 'DECLINED'>
| IAuthResponse<{ errorMessage: string }, 'FAILED'>;
Right, this tells us that ParsedAuthorizationResponse
is just a synonym for any one of three different parametrizations of IAuthResponse
. Unfortunately, that doesn't tell us much until we know what IAuthResponse
looks like. Which we do, fortunately:
type IAuthResponse<T, U extends TransactionStatus> = T & {
transactionStatus: U;
};
OK, this gets more concrete. TransactionStatus
is just a synonym for a couple of literal strings, and T & { transactionStatus: U; }
is a type conjunction, meaning that the result is a type that is just like the type T
, plus a field transactionStatus
which is of type U
(which with U extends TransactionStatus
is constrained to be one or more of the strings we know as TransactionStatus
).
So what does something like IAuthResponse<{ errorMessage: string }, 'FAILED'>
mean? Well, looking at IAuthResponse
, it expands to this:
{ errorMessage: string } & { transactionStatus: 'FAILED' }
which is the same as
{ errorMessage: string; transactionStatus: 'FAILED' }
Which means that ParsedAuthorizationResponse
actually looks like this:
type ParsedAuthorizationResponse =
| { processorTransactionId: string; transactionStatus: 'AUTHORIZED' | 'CANCELLED' | 'SETTLING' | 'SETTLED' }
| { declineReason: string; transactionStatus: 'DECLINED' }
| { errorMessage: string; transactionStatus: 'FAILED' }
So, creating an object conforming to ParsedAuthorizationResponse
is really easy, it's just object literals:
- If it's failed, it's an object with
transactionStatus: 'FAILED'
and an arbitrary errorMessage
string
- If it's declined, you have
transactionStatus: 'DECLINED'
and an arbitrary declineMessage
string
- Else, it has
transactionStatus
set to one of 'AUTHORIZED'
, 'CANCELLED'
, 'SETTLING'
, or 'SETTLED'
, plus a processorTransactionId
which is a string that I assume you get along with the status of the transaction.
Your example would end up something like this:
async authorize(
request: RawAuthorizationRequest<ClientIDSecretCredentials, PayPalOrder>,
): Promise<ParsedAuthorizationResponse> {
// The response needs to contain status and transaction ID
const { status, processorTransactionId } = JSON.parse(await response) as { status: string; processorTransactionId: string; }
switch (status) {
case 'COMPLETE':
return { transactionStatus: 'AUTHORIZED', processorTransactionId };
case 'VOIDED':
return { transactionStatus: 'CANCELLED', processorTransactionId };
// TODO: Fill in more cases here...
default:
// Unknown status, hopefully shouldn't happen, but for the sake of
// argument, let's pretend that failing the transaction is a reasonable
// thing to do here, just to show how to return an error message
return { transactionStatus: 'FAILED', errorMessage: 'Unknown status: ' + status };
}
}