stripe.customers.retrieve causing issues as it is now returning Stripe.Customer | Stripe.DeletedCustomer

Viewed 987

I am upgrading to the latest Stripe API version (2020-03-02) and I am not sure how to access the values on my customer object as it now just shows the union of the properties between Stripe.Customer and Stripe.DeletedCustomer.

Any tips on how to check the type and convert to a Stripe.Customer type?

I am getting the following error:

Property 'metadata' does not exist on type 'Customer | DeletedCustomer'. Property 'metadata' does not exist on type 'DeletedCustomer'.

 const customer: Stripe.Customer | Stripe.DeletedCustomer = await stripe.customers.retrieve(customerId);
 const uid = customer.metadata.firebaseUID;

Note that Customer and DeletedCustomer are interfaces:

namespace Stripe {
     interface DeletedCustomer {
          id: string;
          object: 'customer';
          deleted: true;
        }
    
     interface Customer {
          id: string;
          metadata: Metadata;
    ...
    }
}
3 Answers

For differentiating types, you can:

  1. Check if a not shared property exists in the needed object,
  2. (or/and) Compare a/this property value

In your case, the Stripe.DeletedCustomer not have the metadata property, you can therefore simply verify that this property exists, if so then the "customer" is of type "Stripe.Customer" else is of type "Stripe.DeletedCustomer":

const customer: Stripe.Customer | Stripe.DeletedCustomer = await stripe.customers.retrieve(customerId);

if(customer instanceof Object && "metadata" in customer) {
 // $customer is of type "Stripe.Customer"
 const uid = customer.metadata.firebaseUID;
}
else {
 // $customer is of type "Stripe.DeletedCustomer
}

@see: https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types

Stripe provides a common deleted flag that you can use to determine if you have a Customer or DeletedCustomer.

// You don't need the explicit type, it's inferred
const customer = await stripe.customers.retrieve(customerId);
if (!customer.deleted) {
   const uid = customer.metadata.firebaseUID;
   ...
}

See this GitHub issue for more information.

I found this comment for discriminating between Stripe.Customer and Stripe.DeletedCustomer.

So this worked for me:

if (customer.deleted === true) {
  // TypeScript treats customer as Stripe.DeletedCustomer
} else {
  // TypeScript treats customer as Stripe.Customer
}

I originally tried just if (customer.deleted), but that didn't work. TypeScript only discriminated after I added the === true.

Related