# TypeScript Type Migration Guide ## Overview This guide helps you migrate from the old type patterns to the new unified patterns in `@customer-portal/domain`. ## Quick Migration Reference ### Async State Migration #### Before (Old Pattern) ```typescript // Old way - multiple different patterns interface AsyncState { data: T | null; loading: boolean; error: string | null; } // Usage const [state, setState] = useState>({ data: null, loading: false, error: null, }); // Checking state if (state.loading) { return ; } if (state.error) { return ; } if (state.data) { return ; } ``` #### After (New Pattern) ```typescript // New way - discriminated union import { AsyncState, isLoading, isError, isSuccess } from '@customer-portal/domain'; // Usage const [state, setState] = useState>({ status: 'idle' }); // Checking state with type guards if (isLoading(state)) { return ; } if (isError(state)) { return ; } if (isSuccess(state)) { return ; } ``` ### Form State Migration #### Before (Old Pattern) ```typescript interface FormState { data: T; errors: Record; touched: Record; dirty: boolean; valid: boolean; submitting: boolean; } ``` #### After (New Pattern) ```typescript import { FormState, createFormState, getFormValues } from '@customer-portal/domain'; // Create initial form state const initialState = createFormState({ email: '', password: '', name: '', }); // Get form values const formData = getFormValues(formState); ``` ### API Response Handling #### Before (Multiple Patterns) ```typescript // Different response formats everywhere interface WhmcsResponse { result: 'success' | 'error'; data?: T; message?: string; } interface SalesforceResponse { success: boolean; data?: T; errors?: any[]; } ``` #### After (Unified with Adapters) ```typescript import { adaptWhmcsResponse, adaptSalesforceResponse, isSuccessResponse, unwrapResponse } from '@customer-portal/domain'; // Convert different API responses to unified format const whmcsData = adaptWhmcsResponse(whmcsResponse); const sfData = adaptSalesforceResponse(salesforceResponse); // Use unified response handling if (isSuccessResponse(whmcsData)) { console.log('WHMCS data:', whmcsData.data); } // Or unwrap directly (throws on error) const userData = unwrapResponse(whmcsData); ``` ## Step-by-Step Migration Process ### 1. Update Imports Replace old imports: ```typescript // ❌ Old import type { AsyncState } from '../types'; import type { FormState } from '../utils/ui-state'; // ✅ New import type { AsyncState, FormState } from '@customer-portal/domain'; ``` ### 2. Update State Initialization Replace old state initialization: ```typescript // ❌ Old const [userState, setUserState] = useState({ data: null, loading: false, error: null, }); // ✅ New const [userState, setUserState] = useState>({ status: 'idle' }); ``` ### 3. Update State Transitions Replace old state updates: ```typescript // ❌ Old setUserState({ data: null, loading: true, error: null }); setUserState({ data: user, loading: false, error: null }); setUserState({ data: null, loading: false, error: 'Failed to load' }); // ✅ New import { createLoadingState, createSuccessState, createErrorState } from '@customer-portal/domain'; setUserState(createLoadingState()); setUserState(createSuccessState(user)); setUserState(createErrorState('Failed to load')); ``` ### 4. Update State Checks Replace old state checks: ```typescript // ❌ Old if (state.loading) { /* ... */ } if (state.error) { /* ... */ } if (state.data) { /* ... */ } // ✅ New import { isLoading, isError, isSuccess } from '@customer-portal/domain'; if (isLoading(state)) { /* ... */ } if (isError(state)) { /* ... */ } if (isSuccess(state)) { /* ... */ } ``` ### 5. Update Form Handling Replace old form state: ```typescript // ❌ Old const [formState, setFormState] = useState({ data: { email: '', password: '' }, errors: {}, touched: {}, dirty: false, valid: true, submitting: false, }); // ✅ New import { createFormState, updateFormField } from '@customer-portal/domain'; const [formState, setFormState] = useState( createFormState({ email: '', password: '' }) ); // Update field const updatedState = { ...formState, email: updateFormField(formState.email, newValue), }; ``` ## Migration Helpers ### Temporary Compatibility If you need to migrate gradually, use the migration helpers: ```typescript import { migrateAsyncState, legacyAsyncState } from '@customer-portal/domain'; // Convert old state to new state const newState = migrateAsyncState(oldState); // Convert new state back to old format (for backward compatibility) const oldState = legacyAsyncState(newState); ``` ### Custom Hooks Migration Update your custom hooks: ```typescript // ❌ Old function useUser(id: string) { const [state, setState] = useState({ data: null, loading: false, error: null, }); useEffect(() => { setState({ data: null, loading: true, error: null }); fetchUser(id) .then(user => setState({ data: user, loading: false, error: null })) .catch(error => setState({ data: null, loading: false, error: error.message })); }, [id]); return state; } // ✅ New import { AsyncState, createLoadingState, createSuccessState, createErrorState } from '@customer-portal/domain'; function useUser(id: string) { const [state, setState] = useState>({ status: 'idle' }); useEffect(() => { setState(createLoadingState()); fetchUser(id) .then(user => setState(createSuccessState(user))) .catch(error => setState(createErrorState(error.message))); }, [id]); return state; } ``` ## Benefits of Migration ### 1. Type Safety - Impossible states are eliminated (can't have `loading: true` and `data: User` at the same time) - Better IntelliSense and autocomplete - Compile-time error detection ### 2. Consistency - Single pattern across the entire application - Predictable state transitions - Unified error handling ### 3. Developer Experience - Less cognitive load - Easier testing - Better debugging ### 4. Performance - Smaller bundle sizes - Better tree-shaking - Reduced memory usage ## Common Patterns ### Loading States ```typescript // ✅ New pattern function UserProfile({ userId }: { userId: string }) { const userState = useUser(userId); return (
{isLoading(userState) && } {isError(userState) && } {isSuccess(userState) && }
); } ``` ### Form Handling ```typescript // ✅ New pattern function LoginForm() { const [formState, setFormState] = useState( createFormState({ email: '', password: '' }) ); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const formData = getFormValues(formState); try { await login(formData); } catch (error) { // Handle form errors } }; return (
{/* Form fields */}
); } ``` ### API Integration ```typescript // ✅ New pattern with adapters async function fetchUserData(id: string) { const whmcsResponse = await whmcsApi.getClient(id); const unifiedResponse = adaptWhmcsResponse(whmcsResponse); return unwrapResponse(unifiedResponse); } ``` ## Troubleshooting ### Common Issues 1. **Type Errors After Migration** - Make sure to import types from `@customer-portal/domain` - Use type guards instead of direct property access - Update state initialization to use discriminated unions 2. **Runtime Errors** - Check that you're using the correct state transition functions - Ensure proper error handling with the new patterns 3. **Performance Issues** - The new patterns should improve performance - If you see regressions, check for unnecessary re-renders ### Getting Help - Check the implementation examples in `/packages/domain/src/patterns/` - Look at the test files for usage patterns - Refer to the main documentation in `TYPE_STRUCTURE_ANALYSIS_REPORT.md` ## Next Steps After completing the migration: 1. Remove deprecated type definitions 2. Update linting rules to prevent old patterns 3. Add tests for the new patterns 4. Update team documentation and training materials This migration will significantly improve the type safety, consistency, and maintainability of your codebase while providing a better developer experience.