diff --git a/packages/core/src/contexts/ModalContext.ts b/packages/core/src/contexts/ModalContext.ts index 80b37c73..f0cac4b0 100644 --- a/packages/core/src/contexts/ModalContext.ts +++ b/packages/core/src/contexts/ModalContext.ts @@ -1,11 +1,15 @@ import { createContext, Dispatch, SetStateAction } from "react"; -export interface ModalState { - type: any; - props?: any; +export interface ModalState { + type: T; + props?: P; } -export const ModalStateContext = createContext(null); +export const ModalStateContext = createContext | null>(null); + export const ModalSetterContext = createContext + SetStateAction> > | null>(null); diff --git a/packages/core/src/hooks/useModal.ts b/packages/core/src/hooks/useModal.ts index 7a33197c..c5dbced0 100644 --- a/packages/core/src/hooks/useModal.ts +++ b/packages/core/src/hooks/useModal.ts @@ -1,19 +1,19 @@ import { useContext } from "react"; import { ModalSetterContext, ModalState } from "../contexts/ModalContext"; -export const useModal = () => { +export const useModal = () => { const setModalState = useContext(ModalSetterContext); if (!setModalState) { throw new Error("useModal must be used within a ModalProvider"); } - const openModal = ({ type, props = null }: ModalState) => { - setModalState({ type, props }); + const openModal = (modalState: ModalState) => { + setModalState(modalState); }; const closeModal = () => { - setModalState({ type: null, props: null }); + setModalState({ type: null, props: null } as ModalState); }; return { openModal, closeModal }; diff --git a/packages/core/src/providers/ModalProvider.tsx b/packages/core/src/providers/ModalProvider.tsx index 9b42bdc8..fafe2f0f 100644 --- a/packages/core/src/providers/ModalProvider.tsx +++ b/packages/core/src/providers/ModalProvider.tsx @@ -5,7 +5,10 @@ interface ModalProviderProps { } export const ModalProvider = ({ children }: ModalProviderProps) => { - const [state, setState] = useState({ type: null, props: null }); + const [state, setState] = useState>({ + type: null, + props: null, + }); return ( diff --git a/packages/service/src/common/components/ModalContainer/ModalContainer.tsx b/packages/service/src/common/components/ModalContainer/ModalContainer.tsx index 4eac41f6..cfb20d1e 100644 --- a/packages/service/src/common/components/ModalContainer/ModalContainer.tsx +++ b/packages/service/src/common/components/ModalContainer/ModalContainer.tsx @@ -15,6 +15,7 @@ import { DescriptionModalProps, } from "./modal"; +// ModalType 정의 export type ModalType = | "login" | "alert" @@ -23,11 +24,13 @@ export type ModalType = | "confirm" | "description"; +// DefaultModalProps 정의 export interface DefaultModalProps { isOpen: boolean; onRequestClose: () => void; } +// ModalComponentMap 인터페이스 정의 interface ModalComponentMap { login: React.FC; alert: React.FC; @@ -37,6 +40,7 @@ interface ModalComponentMap { description: React.FC; } +// MODAL_COMPONENT_MAP 구현 const MODAL_COMPONENT_MAP: ModalComponentMap = { login: GoogleLoginModal, alert: AlertModal, @@ -46,27 +50,51 @@ const MODAL_COMPONENT_MAP: ModalComponentMap = { description: DescriptionModal, }; +// ModalStateMap 정의 +export interface ModalStateMap { + login: DefaultModalProps; + alert: AlertModalProps; + pending: DefaultModalProps; + navigate: NavigateModalProps; + confirm: ConfirmModalProps; + description: DescriptionModalProps; +} + +// ModalState 제네릭 타입 정의 +export interface ModalState { + type: T; + props?: ModalStateMap[T]; +} + +// ModalContainer 컴포넌트 정의 export const ModalContainer = () => { const { closeModal } = useModal(); - const modalState = useContext(ModalStateContext); + const modalState = useContext( + ModalStateContext, + ) as ModalState | null; if (!modalState || !modalState.type) { return null; } + // modalState의 type과 props를 구체적으로 타입 캐스팅 const { type, props } = modalState; - const ModalComponent = MODAL_COMPONENT_MAP[type as ModalType]; + // ModalComponent를 동적으로 선택 + const ModalComponent = MODAL_COMPONENT_MAP[type] as React.FC< + ModalStateMap[typeof type] + >; if (!ModalComponent) { return null; } + // modalProps 정의 const modalProps = { ...props, - isOpen: !!modalState.type, // boolean 보장을 위해 !! 사용 + isOpen: Boolean(modalState.type), onRequestClose: closeModal, - }; + } as ModalStateMap[typeof type]; // modalProps 타입 지정 return createPortal( ,