~/logs/3
root@zourdy:~$ cat log_003.md
> status: [ACTIVE] [FEATURED: FALSE]
> category: FRONTEND
> views: 3,421
Frontend

> Advanced TypeScript Patterns for React Applications_

[ABSTRACT] Master advanced TypeScript patterns and techniques to build type-safe, maintainable React applications with better developer experience.

Michael Rodriguez|TypeScript Specialist
1/5/2024
15 min read
3,421 views
#TypeScript#React#Patterns#Type Safety

> Advanced TypeScript Patterns for React Applications

TypeScript has become essential for building robust React applications. Let's explore advanced patterns that will elevate your code quality and developer experience.

> Generic Components and Props

> Creating Flexible Generic Components

tsx.sh
// Generic List Component
interface ListProps<T> {
  items: T[]
  renderItem: (item: T, index: number) => React.ReactNode
  keyExtractor: (item: T) => string | number
  emptyMessage?: string
  className?: string
}

export function List<T>({
  items,
  renderItem,
  keyExtractor,
  emptyMessage = "No items found",
  className = ""
}: ListProps<T>) {
  if (items.length === 0) {
    return (
      <div className={`text-gray-500 text-center py-8 ${className}`}>
        {emptyMessage}
      </div>
    )
  }

  return (
    <div className={className}>
      {items.map((item, index) => (
        <div key={keyExtractor(item)}>
          {renderItem(item, index)}
        </div>
      ))}
    </div>
  )
}

// Usage
interface User {
  id: number
  name: string
  email: string
}

export function UserList({ users }: { users: User[] }) {
  return (
    <List
      items={users}
      keyExtractor={(user) => user.id}
      renderItem={(user) => (
        <div className="p-4 border rounded">
          <h3>{user.name}</h3>
          <p>{user.email}</p>
        </div>
      )}
      emptyMessage="No users found"
    />
  )
}

> Advanced Hook Patterns

> Custom Hook with Generic Return Types

tsx.sh
// Generic API Hook
interface UseApiResult<T> {
  data: T | null
  loading: boolean
  error: string | null
  refetch: () => Promise<void>
}

export function useApi<T>(url: string): UseApiResult<T> {
  const [data, setData] = useState<T | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  const fetchData = useCallback(async () => {
    try {
      setLoading(true)
      setError(null)
      
      const response = await fetch(url)
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`)
      }
      
      const result = await response.json()
      setData(result)
    } catch (err) {
      setError(err instanceof Error ? err.message : 'An error occurred')
    } finally {
      setLoading(false)
    }
  }, [url])

  useEffect(() => {
    fetchData()
  }, [fetchData])

  return { data, loading, error, refetch: fetchData }
}

// Usage with specific types
interface Post {
  id: number
  title: string
  content: string
  author: string
}

export function PostList() {
  const { data: posts, loading, error } = useApi<Post[]>('/api/posts')

  if (loading) return <div>Loading...</div>
  if (error) return <div>Error: {error}</div>

  return (
    <List
      items={posts || []}
      keyExtractor={(post) => post.id}
      renderItem={(post) => (
        <article className="p-6 border rounded-lg">
          <h2 className="text-xl font-bold">{post.title}</h2>
          <p className="text-gray-600">By {post.author}</p>
          <p className="mt-2">{post.content}</p>
        </article>
      )}
    />
  )
}

> Discriminated Unions for State Management

> Type-Safe State Patterns

tsx.sh
// Define state types using discriminated unions
type AsyncState<T> =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error'; error: string }

// Reducer for async operations
type AsyncAction<T> =
  | { type: 'FETCH_START' }
  | { type: 'FETCH_SUCCESS'; payload: T }
  | { type: 'FETCH_ERROR'; payload: string }
  | { type: 'RESET' }

function asyncReducer<T>(
  state: AsyncState<T>,
  action: AsyncAction<T>
): AsyncState<T> {
  switch (action.type) {
    case 'FETCH_START':
      return { status: 'loading' }
    case 'FETCH_SUCCESS':
      return { status: 'success', data: action.payload }
    case 'FETCH_ERROR':
      return { status: 'error', error: action.payload }
    case 'RESET':
      return { status: 'idle' }
    default:
      return state
  }
}

// Custom hook using the reducer
export function useAsyncData<T>(fetchFn: () => Promise<T>) {
  const [state, dispatch] = useReducer(asyncReducer<T>, { status: 'idle' })

  const execute = useCallback(async () => {
    dispatch({ type: 'FETCH_START' })
    try {
      const data = await fetchFn()
      dispatch({ type: 'FETCH_SUCCESS', payload: data })
    } catch (error) {
      dispatch({
        type: 'FETCH_ERROR',
        payload: error instanceof Error ? error.message : 'Unknown error'
      })
    }
  }, [fetchFn])

  const reset = useCallback(() => {
    dispatch({ type: 'RESET' })
  }, [])

  return { state, execute, reset }
}

> Advanced Component Patterns

> Render Props with TypeScript

tsx.sh
// Render props pattern with strong typing
interface RenderPropsComponentProps<T> {
  data: T[]
  children: (props: {
    items: T[]
    selectedItem: T | null
    selectItem: (item: T) => void
    clearSelection: () => void
  }) => React.ReactNode
}

export function SelectableList<T extends { id: string | number }>({
  data,
  children
}: RenderPropsComponentProps<T>) {
  const [selectedItem, setSelectedItem] = useState<T | null>(null)

  const selectItem = useCallback((item: T) => {
    setSelectedItem(item)
  }, [])

  const clearSelection = useCallback(() => {
    setSelectedItem(null)
  }, [])

  return (
    <>
      {children({
        items: data,
        selectedItem,
        selectItem,
        clearSelection
      })}
    </>
  )
}

// Usage
interface Product {
  id: number
  name: string
  price: number
}

export function ProductSelector({ products }: { products: Product[] }) {
  return (
    <SelectableList data={products}>
      {({ items, selectedItem, selectItem, clearSelection }) => (
        <div className="space-y-4">
          <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
            {items.map((product) => (
              <button
                key={product.id}
                onClick={() => selectItem(product)}
                className={`p-4 border rounded-lg transition-colors ${
                  selectedItem?.id === product.id
                    ? 'border-blue-500 bg-blue-50'
                    : 'border-gray-200 hover:border-gray-300'
                }`}
              >
                <h3 className="font-semibold">{product.name}</h3>
                <p className="text-gray-600">${product.price}</p>
              </button>
            ))}
          </div>
          
          {selectedItem && (
            <div className="p-4 bg-green-50 border border-green-200 rounded-lg">
              <h4 className="font-semibold">Selected: {selectedItem.name}</h4>
              <p>Price: ${selectedItem.price}</p>
              <button
                onClick={clearSelection}
                className="mt-2 px-3 py-1 bg-red-500 text-white rounded"
              >
                Clear Selection
              </button>
            </div>
          )}
        </div>
      )}
    </SelectableList>
  )
}

> Type Guards and Utility Types

> Custom Type Guards

tsx.sh
// Type guards for runtime type checking
interface User {
  id: number
  name: string
  email: string
  role: 'admin' | 'user'
}

interface AdminUser extends User {
  role: 'admin'
  permissions: string[]
}

// Type guard functions
export function isUser(value: unknown): value is User {
  return (
    typeof value === 'object' &&
    value !== null &&
    'id' in value &&
    'name' in value &&
    'email' in value &&
    'role' in value &&
    typeof (value as User).id === 'number' &&
    typeof (value as User).name === 'string' &&
    typeof (value as User).email === 'string' &&
    ['admin', 'user'].includes((value as User).role)
  )
}

export function isAdminUser(user: User): user is AdminUser {
  return user.role === 'admin' && 'permissions' in user
}

// Usage in components
export function UserProfile({ userData }: { userData: unknown }) {
  if (!isUser(userData)) {
    return <div>Invalid user data</div>
  }

  return (
    <div className="p-6 border rounded-lg">
      <h2 className="text-xl font-bold">{userData.name}</h2>
      <p className="text-gray-600">{userData.email}</p>
      <p className="text-sm text-gray-500">Role: {userData.role}</p>
      
      {isAdminUser(userData) && (
        <div className="mt-4">
          <h3 className="font-semibold">Admin Permissions:</h3>
          <ul className="list-disc list-inside">
            {userData.permissions.map((permission) => (
              <li key={permission}>{permission}</li>
            ))}
          </ul>
        </div>
      )}
    </div>
  )
}

> Conclusion

These advanced TypeScript patterns provide the foundation for building robust, type-safe React applications. By leveraging generics, discriminated unions, and proper type guards, you can create more maintainable and reliable code that scales with your application's complexity.

RELATED.LOGS

root@zourdy:~$ ls -la related_logs/
> found 1 related entries
LOG: ACTIVE
VIEWS: 3,421
[LAST_MODIFIED] 1/12/2024, 12:00:00 AM