86484


stripeのサンプルコードをTypeScript化しようとしているのですが、なぜかストリングリテラルが当たる場所でちゃんと文字列を渡しているのにエラーを起こします。

エラー内容 - `options` の箇所で出てきます。

[code]

    Optional Elements configuration options. Once the stripe prop has been set, these options cannot be changed.
    
    Type '{ clientSecret: string; appearance: { theme: string; }; }' is not assignable to type 'StripeElementsOptions'.
      The types of 'appearance.theme' are incompatible between these types.
        Type 'string' is not assignable to type '"stripe" | "night" | "flat" | "none" | undefined'.ts(2322)
    react-stripe.d.ts(445, 5): The expected type comes from property 'options' which is declared here on type 'IntrinsicAttributes & ElementsProps & { children?: ReactNode; }'
    
[/code]

コード

[code]

    import React, { useState, useEffect } from "react";
    import { loadStripe } from "@stripe/stripe-js";
    import { Elements } from "@stripe/react-stripe-js";
    
    import CheckoutForm from "./CheckOutForm";
    import "./App.css";
    
    // Make sure to call loadStripe outside of a component’s render to avoid
    // recreating the Stripe object on every render.
    // loadStripe is initialized with a fake API key.
    // Sign in to see examples pre-filled with your key.
    const stripePromise = loadStripe('pk_test_46zswMCbz39W2KAqKj43vDRu')
    
    export default function App() {
      const [clientSecret, setClientSecret] = useState("");
    
      useEffect(() => {
        // Create PaymentIntent as soon as the page loads
        fetch("/create-payment-intent", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ items: [{ id: "xl-tshirt" }] }),
        })
          .then((res) => res.json())
          .then((data) => setClientSecret(data.clientSecret));
      }, []);
    
      const appearance = {
        theme: "stripe",
      };
      const options = {
        clientSecret,
        appearance,
      };
    
      return (
        <div className="App">
          {clientSecret && (
            <Elements stripe={stripePromise} options={options}>
              <CheckoutForm />
            </Elements>
          )}
        </div>
      )
    }
    
    
[/code]

### 追記

型注釈とは下記のように明示的に型を指定してあげるという事でしょうか？

[code]

    type Options = {
      clientSecret: string;
      appearance: {
        theme: 'stripe' | 'night' | 'flat' | 'none';
      }
    }
    
    // 一部抜粋...
    
    const appearance = {
        theme: 'stripe',
      };
      const options : Options = {
        clientSecret,
        appearance,
      };
    
      return (
        <div className="App">
          {clientSecret && (
            <Elements stripe={stripePromise} options={options}>
              <CheckoutForm />
            </Elements>
          )}
        </div>
      )
    
[/code]

追記2  
こういう事ですね！

[code]

    import React, { useState, useEffect } from "react";
    import { loadStripe, StripeElementsOptions, Appearance } from "@stripe/stripe-js";
    import { Elements} from "@stripe/react-stripe-js";
    
    
    import CheckoutForm from "./CheckOutForm";
    import "./App.css";
    
    // Make sure to call loadStripe outside of a component’s render to avoid
    // recreating the Stripe object on every render.
    // loadStripe is initialized with a fake API key.
    // Sign in to see examples pre-filled with your key.
    const stripePromise = loadStripe('pk_test_46zswMCbz39W2KAqKj43vDRu')
    
    export default function App() {
      const [clientSecret, setClientSecret] = useState("");
    
      useEffect(() => {
        // Create PaymentIntent as soon as the page loads
        fetch("/create-payment-intent", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ items: [{ id: "xl-tshirt" }] }),
        })
          .then((res) => res.json())
          .then((data) => setClientSecret(data.clientSecret));
      }, []);
    
      const appearance: Appearance = {
        theme: 'stripe',
      };
      const options : StripeElementsOptions = {
        clientSecret,
        appearance,
      };
    
      return (
        <div className="App">
          {clientSecret && (
            <Elements stripe={stripePromise} options={options}>
              <CheckoutForm />
            </Elements>
          )}
        </div>
      )
    }
    
    
[/code]


CC BY-SA 4.0
2022-02-20T12:59:39.173
86480
2022-02-20T14:47:03.947
2022-02-20T14:47:03.947
22565
22565
question
javascript reactjs typescript
@stripe/react-stripe-jsで特定の文字列を渡しているが、ストリングリテラルでエラーになる


`options.appearance.theme` につく型の説明として、

  * `"stripe" | "night" | "flat" | "none" | undefined`：書かれている文字列リテラルのどれかか `undefined` かが期待されている
  * `string`：何かしら文字列が期待されている

となっているところ、前者の型がつく場所に後者の型がつく値を代入しようとしているのでエラーになっていそうです。後者の型は任意の文字列を許している一方、前者はそうではないからです。

で、前者の型は `Elements` を提供している `@stripe/react-stripe-js` から来ていて後者の型は引数に渡している変数
`options` から来ているので、自分で用意している `options`
の型を明示的に詳細に付けてあげると良さそうです。文字列リテラルを渡している箇所でも、そこで型注釈なしに推論される型は `string`
であることに注意してください。後から変更されうるからです。簡単には、`StripeElementsOptions` で型注釈してあげると良さそうです。


CC BY-SA 4.0
2022-02-20T13:28:22.103
86484
2022-02-20T14:24:26.563
2022-02-20T14:24:26.563
19110
19110
86480
answer