[@types/react-stripe-elements] Update createToken to accept BankAccountOptions as well (#41946)

* Update react-stripe-elements definitions to allow BankAccountOptions to be passed to createToken
Also add some tests for the Iban, IdealBank and PaymentRequestButton elements

* Update stripe-v3 to accept BankAccountOptions on createToken
This commit is contained in:
Benedikt Bauer 2020-02-03 19:21:24 +01:00 committed by GitHub
parent 5706c529a4
commit b280439d65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 24 deletions

View File

@ -11,6 +11,7 @@
// Maciej Dabek <https://github.com/bombek92>
// Hiroshi Ioka <https://github.com/hirochachacha>
// Austin Turner <https://github.com/paustint>
// Benedikt Bauer <https://github.com/mastacheata>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 3.5
@ -18,6 +19,7 @@
import * as React from 'react';
export namespace ReactStripeElements {
import BankAccountTokenOptions = stripe.BankAccountTokenOptions;
type ElementChangeResponse = stripe.elements.ElementChangeResponse;
type ElementsOptions = stripe.elements.ElementsOptions;
// From https://stripe.com/docs/stripe-js/reference#element-types
@ -28,14 +30,6 @@ export namespace ReactStripeElements {
type SourceOptions = stripe.SourceOptions;
type HTMLStripeElement = stripe.elements.Element;
/**
* There's a bug in @types/stripe which defines the property as
* `declined_code` (with a 'd') but it's in fact `decline_code`
*/
type PatchedTokenResponse = TokenResponse & {
error?: { decline_code?: string };
};
interface StripeProviderOptions {
stripeAccount?: string;
}
@ -44,7 +38,12 @@ export namespace ReactStripeElements {
| { apiKey?: never; stripe: stripe.Stripe | null } & StripeProviderOptions;
interface StripeOverrideProps {
createToken(options?: TokenOptions): Promise<PatchedTokenResponse>;
/*
* react-stripe-elements let's you use the same createToken function
* with either credit card or bank account options
* which one to choose depends solely on the inferred elements and can't be expressed in TypeScript
*/
createToken(options?: TokenOptions | BankAccountTokenOptions): Promise<TokenResponse>;
createSource(sourceData?: SourceOptions): Promise<SourceResponse>;
createPaymentMethod(
paymentMethodType: stripe.paymentMethod.paymentMethodType,

View File

@ -8,7 +8,10 @@ import {
CardExpiryElement,
CardCvcElement,
CardCVCElement,
IbanElement,
IdealBankElement,
PostalCodeElement,
PaymentRequestButtonElement,
ReactStripeElements,
} from 'react-stripe-elements';
import InjectedStripeProps = ReactStripeElements.InjectedStripeProps;
@ -16,8 +19,8 @@ import InjectedStripeProps = ReactStripeElements.InjectedStripeProps;
import ElementChangeResponse = stripe.elements.ElementChangeResponse;
import ElementsOptions = stripe.elements.ElementsOptions;
import ElementsCreateOptions = stripe.elements.ElementsCreateOptions;
import PatchedTokenResponse = ReactStripeElements.PatchedTokenResponse;
import HTMLStripeElement = ReactStripeElements.HTMLStripeElement;
import TokenResponse = ReactStripeElements.TokenResponse;
const cardElementProps: ElementsOptions = {
iconStyle: 'solid',
@ -65,9 +68,7 @@ const fontElementsProps: ElementsCreateOptions = {
locale: 'es',
};
<CardElement {...cardElementProps} onReady={(el: HTMLStripeElement) => el.clear()} />;
const ElementsWithPropsTest: React.SFC = () => (
const ElementsWithPropsTest: React.FC = () => (
<div>
<CardElement
{...cardElementProps}
@ -104,6 +105,20 @@ const ElementsWithPropsTest: React.SFC = () => (
onReady={(el: HTMLStripeElement) => void 0}
onFocus={(event: ElementChangeResponse) => void 0}
/>
<IbanElement
{...cardElementProps}
onChange={(event: ElementChangeResponse) => void 0}
onBlur={(event: ElementChangeResponse) => void 0}
onReady={(el: HTMLStripeElement) => void 0}
onFocus={(event: ElementChangeResponse) => void 0}
/>
<IdealBankElement
{...cardElementProps}
onChange={(event: ElementChangeResponse) => void 0}
onBlur={(event: ElementChangeResponse) => void 0}
onReady={(el: HTMLStripeElement) => void 0}
onFocus={(event: ElementChangeResponse) => void 0}
/>
<PostalCodeElement
{...cardElementProps}
onChange={(event: ElementChangeResponse) => void 0}
@ -111,11 +126,19 @@ const ElementsWithPropsTest: React.SFC = () => (
onReady={(el: HTMLStripeElement) => void 0}
onFocus={(event: ElementChangeResponse) => void 0}
/>
<PaymentRequestButtonElement
{...cardElementProps}
onChange={(event: ElementChangeResponse) => void 0}
onBlur={(event: ElementChangeResponse) => void 0}
onReady={(el: HTMLStripeElement) => void 0}
onFocus={(event: ElementChangeResponse) => void 0}
onClick={(event: ElementChangeResponse) => void 0}
/>
</div>
);
interface ComponentProps {
tokenCallback(token: PatchedTokenResponse): void;
tokenCallback(token: TokenResponse): void;
}
class WrappedComponent extends React.Component<ComponentProps & InjectedStripeProps> {
@ -141,6 +164,7 @@ class WrappedComponent extends React.Component<ComponentProps & InjectedStripePr
onSubmit = () => {
const elements = this.props.elements;
// createToken(options?: TokenOptions)
this.props
.stripe!.createToken({
name: '',
@ -152,7 +176,19 @@ class WrappedComponent extends React.Component<ComponentProps & InjectedStripePr
address_country: '',
currency: '',
})
.then((response: PatchedTokenResponse) => this.props.tokenCallback(response));
.then((response: TokenResponse) => this.props.tokenCallback(response));
// createToken(options?: BankAccountTokenOptions)
this.props
.stripe!.createToken({
country: '',
currency: '',
routing_number: '',
account_number: '',
account_holder_name: '',
account_holder_type: '',
})
.then((response: TokenResponse) => this.props.tokenCallback(response));
}
isFormValid = () => {
@ -173,7 +209,7 @@ class WrappedComponent extends React.Component<ComponentProps & InjectedStripePr
const ExportedComponent: React.ComponentType<ComponentProps> = injectStripe(WrappedComponent);
class MainComponent extends React.Component {
onTokenReceived = (token: PatchedTokenResponse) => void 0;
onTokenReceived = (token: TokenResponse) => void 0;
render() {
return <ExportedComponent tokenCallback={this.onTokenReceived} />;
@ -195,7 +231,7 @@ class TestHOCs extends React.Component {
/**
* Just an extra test to check default props
*/
const ElementsDefaultPropsTest: React.SFC = () => (
const ElementsDefaultPropsTest: React.FC = () => (
<div>
<CardElement />
<CardNumberElement />
@ -210,9 +246,9 @@ const ElementsDefaultPropsTest: React.SFC = () => (
* StripeProvider should either receive `apiKey` or `stripe`, but not both.
* See: https://github.com/stripe/react-stripe-elements/blob/d30b32b6b8df282dd8880a3521667c371e90083f/src/components/Provider.js#L83-L86
*/
const TestStripeProviderProps1: React.SFC = () => <StripeProvider apiKey="" />;
const TestStripeProviderProps1: React.FC = () => <StripeProvider apiKey="" />;
const TestStripeProviderProps2: React.SFC<{
const TestStripeProviderProps2: React.FC<{
stripe: stripe.Stripe;
}> = props => <StripeProvider stripe={props.stripe} />;
@ -220,7 +256,7 @@ const TestStripeProviderProps2: React.SFC<{
* props.stripe is null until loaded.
* See: https://github.com/stripe/react-stripe-elements#props-shape
*/
const TestStripeProviderProps3: React.SFC<{
const TestStripeProviderProps3: React.FC<{
stripe: stripe.Stripe;
}> = props => <StripeProvider stripe={null} />;
@ -228,7 +264,7 @@ const TestStripeProviderProps3: React.SFC<{
* End-to-end usage of loading stripe.js asynchronously.
* See: https://github.com/stripe/react-stripe-elements#loading-stripejs-asynchronously
*/
const TestStripeProviderProps4: React.SFC<{
const TestStripeProviderProps4: React.FC<{
stripe: null | stripe.Stripe;
}> = props => (
<StripeProvider stripe={props.stripe}>
@ -242,7 +278,7 @@ const TestStripeProviderProps4: React.SFC<{
* StripeProvider should be able to accept options.
* See: https://stripe.com/docs/stripe-js/reference#stripe-function for options.
*/
const TestStripeProviderOptions: React.SFC = () => <StripeProvider apiKey="" stripeAccount="" />;
const TestStripeProviderOptions: React.FC = () => <StripeProvider apiKey="" stripeAccount="" />;
class CreatePaymentMethod extends React.Component<InjectedStripeProps> {
testCreatePaymentMethod = () => {

View File

@ -25,7 +25,7 @@ declare namespace stripe {
interface Stripe {
elements(options?: elements.ElementsCreateOptions): elements.Elements;
createToken(element: elements.Element, options?: TokenOptions): Promise<TokenResponse>;
createToken(element: elements.Element, options?: TokenOptions | BankAccountTokenOptions): Promise<TokenResponse>;
createToken(name: 'bank_account', options: BankAccountTokenOptions): Promise<TokenResponse>;
createToken(name: 'pii', options: PiiTokenOptions): Promise<TokenResponse>;
createSource(element: elements.Element, options?: { owner?: OwnerInfo }): Promise<SourceResponse>;

View File

@ -130,10 +130,39 @@ describe("Stripe elements", () => {
});
it("should create an iban element", () => {
elements.create('iban', {
const ibanElement = elements.create('iban', {
supportedCountries: ['SEPA'],
placeholderCountry: 'AT'
});
stripe.createToken(ibanElement, {
country: 'US',
currency: 'USD',
routing_number: '110000000',
account_number: '110000000',
account_holder_name: 'Jane Austen',
account_holder_type: 'individual',
})
.then((result: stripe.TokenResponse) => {
console.log(result.token);
},
(error: stripe.Error) => {
console.error(error);
});
stripe.createToken('bank_account', {
country: 'US',
currency: 'USD',
routing_number: '110000000',
account_number: '110000000',
account_holder_name: 'Jane Austen',
account_holder_type: 'individual',
})
.then((result: stripe.TokenResponse) => {
console.log(result.token);
},
(error: stripe.Error) => {
console.error(error);
});
});
it("should create an idealBank element", () => {