question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Stripe.Event.Data is too untyped

See original GitHub issue

Currently, when doing stripe.webhooks.constructEvent or stripe.webhooks.constructEventAsync, the event data (which is what we want) is fully untyped. This forces lots of casting, although the type of the event correlates directly with specific stripe objects. We can actually type Stripe.Event so that narrowing event.type (ie, event.type === "payment_intent.succeeded") also narrows the event.data.object and event.data.previous_attributes (for the previous example, Stripe.PaymentIntent).

I’ve been using this in my codebase and it’s helped tremendously. I haven’t been able to use a typescript declaration to override Stripe.Event since declarations union with existing definitions, which keeps Stripe.Event.Data.Object as any no matter what. Can we have the official types use this?

import type Stripe from "stripe";

type WebhookObjects = {
  // https://stripe.com/docs/api/events/types
  [EventName in Exclude<
    Stripe.WebhookEndpointCreateParams.EnabledEvent,
    "*"
  >]: EventName extends `account.application.${string}`
    ? Stripe.Application
    : EventName extends `account.external_account.${string}`
    ? Stripe.Card | Stripe.BankAccount
    : EventName extends `account.${string}`
    ? Stripe.Account
    : EventName extends `application_fee.refund.${string}`
    ? Stripe.FeeRefund
    : EventName extends `application_fee.${string}`
    ? Stripe.ApplicationFee
    : EventName extends `balance.${string}`
    ? Stripe.Balance
    : EventName extends `billing_portal.configuration.${string}`
    ? Stripe.BillingPortal.Configuration
    : EventName extends `capability.${string}`
    ? Stripe.Capability
    : EventName extends `charge.dispute.${string}`
    ? Stripe.Dispute
    : EventName extends `charge.refund.${string}`
    ? Stripe.Refund
    : EventName extends `charge.${string}`
    ? Stripe.Charge
    : EventName extends `checkout.session.${string}`
    ? Stripe.Checkout.Session
    : EventName extends `coupon.${string}`
    ? Stripe.Coupon
    : EventName extends `credit_note.${string}`
    ? Stripe.CreditNote
    : EventName extends `customer.discount.${string}`
    ? Stripe.Discount
    : EventName extends `customer.source.${string}`
    ? Stripe.Discount
    : EventName extends `customer.subscription.${string}`
    ? Stripe.Subscription
    : EventName extends `customer.tax_id.${string}`
    ? Stripe.TaxId
    : EventName extends `customer.${string}`
    ? Stripe.Customer
    : EventName extends `file.${string}`
    ? Stripe.File
    : EventName extends `identity.verification_session.${string}`
    ? Stripe.Identity.VerificationSession
    : EventName extends `invoice.${string}`
    ? Stripe.Invoice
    : EventName extends `invoiceitem.${string}`
    ? Stripe.InvoiceItem
    : EventName extends `issuing_authorization.${string}`
    ? Stripe.Issuing.Authorization
    : EventName extends `issuing_card.${string}`
    ? Stripe.Issuing.Card
    : EventName extends `issuing_cardholder.${string}`
    ? Stripe.Issuing.Cardholder
    : EventName extends `issuing_dispute.${string}`
    ? Stripe.Issuing.Dispute
    : EventName extends `issuing_transaction.${string}`
    ? Stripe.Issuing.Transaction
    : EventName extends `linked_account.${string}`
    ? Stripe.AccountLink
    : EventName extends `mandate.${string}`
    ? Stripe.Mandate
    : EventName extends `order.${string}`
    ? Stripe.Order
    : EventName extends `order_return.${string}`
    ? Stripe.OrderReturn
    : EventName extends `payment_intent.${string}`
    ? Stripe.PaymentIntent
    : EventName extends `payment_link.${string}`
    ? Stripe.PaymentLink
    : EventName extends `payment_method.${string}`
    ? Stripe.PaymentMethod
    : EventName extends `payout.${string}`
    ? Stripe.Payout
    : EventName extends `person.${string}`
    ? Stripe.Person
    : EventName extends `plan.${string}`
    ? Stripe.Plan
    : EventName extends `price.${string}`
    ? Stripe.Price
    : EventName extends `product.${string}`
    ? Stripe.Product
    : EventName extends `promotion_code.${string}`
    ? Stripe.PromotionCode
    : EventName extends `quote.${string}`
    ? Stripe.Quote
    : EventName extends `radar.early_fraud_warning.${string}`
    ? Stripe.Radar.EarlyFraudWarning
    : EventName extends `recipient.${string}`
    ? Stripe.Recipient
    : EventName extends `reporting.report_run.${string}`
    ? Stripe.Reporting.ReportRun
    : EventName extends `reporting.report_type.${string}`
    ? Stripe.Reporting.ReportType
    : EventName extends `review.${string}`
    ? Stripe.Review
    : EventName extends `setup_intent.${string}`
    ? Stripe.SetupIntent
    : EventName extends `sigma.scheduled_query_run.${string}`
    ? Stripe.Sigma.ScheduledQueryRun
    : EventName extends `sku.${string}`
    ? Stripe.Sku
    : EventName extends `source.transaction.${string}`
    ? Stripe.SourceTransaction
    : EventName extends `source.${string}`
    ? Stripe.Source
    : EventName extends `subscription_schedule.${string}`
    ? Stripe.SubscriptionSchedule
    : EventName extends `tax_rate.${string}`
    ? Stripe.TaxRate
    : EventName extends `topup.${string}`
    ? Stripe.Topup
    : EventName extends `transfer.${string}`
    ? Stripe.Transfer
    : never;
};

export type StripeEvent = Omit<Stripe.Event, "data"> &
  {
    [EventName in keyof WebhookObjects]: {
      // Stripe.Event.Data.Object is fully untyped. This will let us type narrow the type of data.object by type.
      data: EventName extends `${string}.updated`
        ? {
            object: WebhookObjects[EventName];
            previous_attributes: Partial<WebhookObjects[EventName]>;
          }
        : {
            object: WebhookObjects[EventName];
          };
      type: EventName;
    };
  }[keyof WebhookObjects];

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:3
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
saiichihashimotocommented, Mar 30, 2022

That’s fair! I still think some intermediate would be good, event if Stripe.Event.Data was just a union of all of those types. Currently there’s no version of narrowing types, the only path is forced casting. I’m wondering if there’s an iterative path that leads to typing this based on all the factors.

0reactions
kamil-stripecommented, Jul 15, 2022

To keep things keep I’m going to close this as a duplicate. Please track related work in https://github.com/stripe/stripe-node/issues/758.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Types of events – curl - Stripe API reference
Occurs when a payment intent using a delayed payment method fails. checkout.session.async_payment_succeeded data.object is a checkout session.
Read more >
json.deserializeuntyped
Thomas Asks: How to loop trough second level deserializeUntyped Json String [duplicate] ... This tool is secure as no data is transmited over...
Read more >
How to identify customer with stripe webhook in Python/Flask
I've created few plans and saved Stripe subscription.id and customer id into my database. Now I am creating webhook to receive JSON data...
Read more >
TypeScript typings for Stripe Webhook Events - Kishan Gajera
The type field is a string type. The type field will store the event type name, for example charge.succeeded . · The data.object...
Read more >
Creating an order in the database with Stripe webhooks
Watch Part 1 - Stripe Payment: https://youtu.be/72iEz5iopqQFull Course: ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found