Home > Net >  What is the best way to check which object is returned from an API in typescript?
What is the best way to check which object is returned from an API in typescript?

Time:11-03

Stripe can return 3 different object types from as the customer. I want the customer id which is what is normally returned.

What I have below is pretty ugly.

Is there a better way to do this?

  const stripeCustomer: string | Stripe.Customer | Stripe.DeletedCustomer = checkoutSession.customer;
  let stripeCustomerId: string;

  if (stripeCustomer instanceof Object && "email" in stripeCustomer) {
    // customer is of type Stripe.Customer
      stripeCustomerId = stripeCustomer.id;
  } else if (typeof stripeCustomer === 'string') { 
    // customer is id
    stripeCustomerId = stripeCustomer;
  } else {
    // customer is of type Stripe.DeletedCustomer
    stripeCustomerId = null;
  }

CodePudding user response:

You can use a user-defined type guards, which let your plug your own custom type-checking logic into the type system.

When they're true for an object, they inform the flow-sensitive typing that the object has the specified type:

function isStripeCustomer(object: any): object is Stripe.Customer {
    return object instanceof Object 
       && "object" in object 
       && object.object === 'customer' 
       && !object.deleted
}

function isStripCustomerID(object: any): object is string {
    return typeof object === "string"
}

function isStripeDeletedCustomer(object: any): object is Stripe.DeletedCustomer {
    return object instanceof Object
       && "object" in object 
       && object.object === 'customer' 
       && object.deleted
}

const customer: string | Stripe.Customer | Stripe.DeletedCustomer = checkoutSession.customer;

let stripeCustomerId: string | null

if (isStripeCustomer(customer)) {
    stripeCustomerId = customer.id
} else if (isStripCustomerID(customer)) { 
    stripeCustomerId = customer;
} else if (isStripeDeletedCustomer(customer) {
    stripeCustomerId = null;
} else {
    // It was none of the known types. Perhaps a new type of result was
    // add in a future version of their API?

}

CodePudding user response:

The basic concept you use is the right one. You can enhance it with typeguards to make it type-safe and allow to identify issues at compile-time:

interface Customer {
    id: string;
}

type CustomerResponse = Customer | string | null;

function isCustomerObject(customer: CustomerResponse): customer is Customer {
    return customer != null && typeof customer === "object" && customer.id != null;
}

function isString(str: CustomerResponse): str is string {
    return typeof str === "string";
}

function identify(obj: Customer | string | null) {
    if (isCustomerObject(obj)) {
        console.log(obj, "is a customer with ID", obj.id);
    } else if (isString(obj)) {
        console.log(obj, "is a string with value", obj);
    } else {
        console.log(obj, "is null");
    }
}

const customerObject: Customer = {
    id: "123"
};


identify(customerObject);
identify("123");
identify(null);

See the same code on the TypeScript Playground.

  • Related