Assist_Design/MIGRATION_GUIDE.md

394 lines
8.6 KiB
Markdown
Raw Normal View History

# 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<T> {
data: T | null;
loading: boolean;
error: string | null;
}
// Usage
const [state, setState] = useState<AsyncState<User>>({
data: null,
loading: false,
error: null,
});
// Checking state
if (state.loading) {
return <LoadingSpinner />;
}
if (state.error) {
return <ErrorMessage error={state.error} />;
}
if (state.data) {
return <UserProfile user={state.data} />;
}
```
#### After (New Pattern)
```typescript
// New way - discriminated union
import { AsyncState, isLoading, isError, isSuccess } from '@customer-portal/domain';
// Usage
const [state, setState] = useState<AsyncState<User>>({ status: 'idle' });
// Checking state with type guards
if (isLoading(state)) {
return <LoadingSpinner />;
}
if (isError(state)) {
return <ErrorMessage error={state.error} />;
}
if (isSuccess(state)) {
return <UserProfile user={state.data} />;
}
```
### Form State Migration
#### Before (Old Pattern)
```typescript
interface FormState<T> {
data: T;
errors: Record<keyof T, string | undefined>;
touched: Record<keyof T, boolean>;
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<T> {
result: 'success' | 'error';
data?: T;
message?: string;
}
interface SalesforceResponse<T> {
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<AsyncState<User>>({
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<AsyncState<User>>({ 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 (
<div>
{isLoading(userState) && <LoadingSpinner />}
{isError(userState) && <ErrorMessage error={userState.error} />}
{isSuccess(userState) && <UserDetails user={userState.data} />}
</div>
);
}
```
### 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 onSubmit={handleSubmit}>
{/* Form fields */}
</form>
);
}
```
### 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.