🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

1回答

864閲覧

Redux内オブジェクトの値を使用して、それを別のオブジェクトのキーとして使用したい。

at3250

総合スコア8

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2021/01/17 18:24

編集2021/01/19 22:03

実現したいこと

Reduxのステートに格納してあるログイン時に取得したuserオブジェクトから、メールアドレスを抽出し、そのメールアドレスをキーとしてtokenDict内のトークンを取得したい。なお、ログイン時に格納したuserからはemailのみが必要なため、userInfoインターフェース内はemailのみとなっている。

発生している問題

問題としては、userEmailをtokenDictの引数として渡した際に、userInfoのインターフェース内のemailに?をつけなければ、"Property 'email' is missing in type '{}' but required in type 'userInfo'."というエラーが出てしまい、?をつけると"Property 'email' of type 'string | undefined' is not assignable to string index type 'string'."というエラーが出てしまっていて立ち止まっています。2つ目のエラーはオブジェクトのキーがundefinedを許すことはpropertyがemailのみということもあり、許されないことは理解しております。エラーとログイン時に返ってくるUserオブジェクトは以下のスクリーンショットの通りになります。イメージ説明

コード

Typescript

1//tokenDict.tsx 2export const tokenDict: { [email: string]: string } = { 3 "user1@example.com": "sample_token1", 4 "user2@example.com": "sample_token2", 5};

Typescript

1//HomeScreen.tsx 2interface userInfo { 3 email: string; //email vs email? 4 [key: string]: string; 5} 6const HomeScreen: React.FC = () => { 7 const user: userInfo = useGlobalState("user"); //user object returned from login process is stored in user state in Redux. 8 const userEmail: string = user.email; 9 const token = tokenDict[userEmail]; 10

TypeScript

1//App.tsx 2const App: React.FC = () => { 3 const user = useGlobalState("user"); 4 const dispatch = useDispatch(); 5 6 useEffect(() => { 7 const unsubscribe = auth.onAuthStateChanged((authUser) => { 8 if (authUser) { 9 dispatch({ 10 type: "SET_USER", 11 user: authUser, 12 }); 13 } else { 14 dispatch({ 15 type: "SET_USER", 16 user: {}, 17 }); 18 } 19 }); 20 return () => { 21 unsubscribe(); 22 }; 23 }, []); 24 25 return ( 26 <Router> 27 <div className="app"> 28 <Switch> 29 <Route path="/login"> 30 <Header /> 31 <Login /> 32 </Route> 33 <Route path="/"> 34 <Header /> 35 <div className="app__mainscreen"> 36 <ChatScreen /> 37 </div> 38 </Route> 39 </Switch> 40 </div> 41 </Router> 42 ); 43}; 44 45export default App; 46

TypeScript

1//reducer.tsx 2export const initialState = { 3 user: {}, 4}; 5export type State = typeof initialState; 6 7export type Action = { type: "SET_USER"; user: {} }; 8 9export const reducer = (state: State, action: Action) => { 10 switch (action.type) { 11 case "SET_USER": 12 return { 13 ...state, 14 user: action.user, 15 }; 16 default: 17 return state; 18 } 19}; 20 21export default reducer; 22

TypeScript

1//StateProvider.tsx 2import React, { createContext, useContext, useReducer } from "react"; 3import { Action, initialState, reducer, State } from "./reducer"; 4 5const stateContext = createContext(initialState); 6const dispatchContext = createContext((() => 0) as React.Dispatch<Action>); 7 8export const Provider: React.ComponentType = ({ children }) => { 9 const [state, dispatch] = useReducer(reducer, initialState); 10 return ( 11 <dispatchContext.Provider value={dispatch}> 12 <stateContext.Provider value={state}>{children}</stateContext.Provider> 13 </dispatchContext.Provider> 14 ); 15}; 16 17export const useDispatch = () => { 18 return useContext(dispatchContext); 19}; 20 21export const useGlobalState = <K extends keyof State>(property: K) => { 22 const state = useContext(stateContext); 23 return state[property]; 24};

補足情報

  • TypeScript
  • React

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

どの箇所でエラーがでているのか、また、あなたのコードすべてを知らないので、これは推測ですが、おそらくuseGlobalState("user")から空のオブジェクトが返ってきているため、userInfoの定義と合わず、エラーを起こしているのではないでしょうか?

以下、確認してみてください:

  • useGlobalStateフックの使い方は正しいか (多くの場合、stateを更新するフックは、useStateと同じように、state自身とそのstateを更新する関数の2つを配列で返します。)
  • useGlobalState("user");から返ってくる型はuserInfoに一致するか
  • user stateは常にemailプロパティを持っているか

追記

  • User stateの初期値が { email: "" } の場合

reducer.tsにて、まずUser typeを定義すると使い回せるので楽です。上記の場合、User stateは常にemailプロパティが必要になります。

ts

1// reducer.ts 2type User = { 3 email: string; 4} 5export type State = { 6 user: User; 7}; 8export const initialState: State = { 9 user: { email: "" }, 10}; 11export type Action = { type: "SET_USER"; user: User };

ts

1// userを初期化 2dispatch({ 3 type: "SET_USER", 4 user: { email: "" }, 5});

ts

1 const user = useGlobalState("user"); //user object returned from login process is stored in user state in Redux. 2 const userEmail = user.email 3 const token = tokenDict[userEmail]

投稿2021/01/18 00:41

編集2021/01/20 07:13
uraway_

総合スコア116

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

at3250

2021/01/19 22:28 編集

ご回答ありがとうございます。先ほど、ほぼ全てののソースコードとUserオブジェクトの返り値を追加いたしました。Urawayさんがご指摘してくださった最後の確認点で、reducerないのinitialStateをUserの返り値と合わせていたため、その部分がエラーの大本になってそうです。ただ、initialState = {user: {email:""}}でtype Action = {type: "SET_USER"; user: {email:string}}にするとApp.tsxのUseEffect内にあるdispatchのuserのところにエラーが出ていて、Type User is not assignable to {email: string}と出てしまいます。他にも色々とリサーチしたりしていますが、自分のTSへの知識不足もあり、いまだにこの問題を解消できていません。もし何か解消への手がかりがありましたら、ご教示いただけると非常に幸いです。よろしくお願いいたします。*コードブロック機能がコメントには無いみたいで、読みづらくなってしまい申し訳ありません。
uraway_

2021/01/20 07:13

その変更により、user stateは常にemailプロパティが必須になったので、user stateを空にする処理の行う際にも、emailプロパティが必要です。追記したので、ご確認ください
at3250

2021/01/21 00:41

ご丁寧なご説明をしてくださり感謝しております。uraway様のご協力により、無事にバグが解消され、プログラムが思い通りに動くようになりました。本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問