简体   繁体   中英

How do I return a Promise with this custom type in TypeScript?

What I can't figure how is how ParsedAuthorizationResponse is implemented and how I can set it's values differently. Eventually, I want to return a certain value/type as a promise.

I thought this would work but it doesn't

let PAR; 
if (status === 'COMPLETED') { 
PAR = new ParsedAuthorizationResponse('AUTHORIZED')
} else throw new Error('Authorization failed')

return Promise<PAR>;
}

//Also tried this but didn't work

type ParsedAuthorizationResponse PAR = 'AUTHORIZED';
return new Promise<PAR>;

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; } 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 };
      }
    }

Returning a promise type is very easy and is not different then returning a promise of a primitive.

Any value you return from an async function will be wrapped with a promise, so:

const returnsANumber = async (): Promise<number> => {
  return 42
}

type Foo = {
  foo: true
}

const returnsAFoo = async (): Promise<Foo> => {
  return {
    foo: true
  }
}

TS playground

In your case just return a ParsedAuthorizationResponse

First, as @thedude said, because your function is already async there is no need to return a Promise, whatever you return will be automatically turned into a Promise.

Now to answer: "How to return a ParsedAuthorizationResponse ".

Starting with the (part of) defintion:

export type ParsedAuthorizationResponse =
  | IAuthResponse<
      { processorTransactionId: string },
      'AUTHORIZED' | 'CANCELLED' | 'SETTLING' | 'SETTLED'
    >

(I'm only going to do this logic with one example of ParsedAuthorisationResponse in the hope you can do the rest)

This says that it's an IAuthResponse<T, U> where T is { processorTransactionId: string } and U is 'AUTHORIZED' | 'CANCELLED' | 'SETTLING' | 'SETTLED' 'AUTHORIZED' | 'CANCELLED' | 'SETTLING' | 'SETTLED'

Slotting this into the defintion of IAuthResponse gives us

type IAuthResponse<T, U extends TransactionStatus> = {
  processorTransactionId: string,
  transactionStatus: 'AUTHORIZED' | 'CANCELLED' | 'SETTLING' | 'SETTLED';
};

Meaning an example of ParsedAuthorizationResponse is

{
  processorTransactionId: "any old string",
  transactionStatus: 'AUTHORIZED',
}

So to return it from your function use something like:

async authorize(
    request: RawAuthorizationRequest<ClientIDSecretCredentials, PayPalOrder>,
  ):ParsedAuthorizationResponse {
      //just imagine I'm gonna get a response that has a value of status in it
      const { status } = JSON.parse(await response)
      
      return {
          processorTransactionId: status, // or whatever
          transactionStatus: 'AUTHORIZED',
      };
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM