From e4c2d3635e2e96db32b214c2112ee0271d1072a2 Mon Sep 17 00:00:00 2001 From: Takeshi Shimada Date: Thu, 30 Oct 2025 23:09:17 +0900 Subject: [PATCH] refactor: Add type constraints to ActionHandler and ActionProcessor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add explicit type constraints to match Feature protocol requirements, ensuring type safety and preventing common errors. Changes: - Add Sendable constraint to Action type parameter - Add AnyObject constraint to State type parameter - Add Sendable constraint to ActionResult type parameter (already present) - Update ActionExecution typealias with same constraints - Add documentation explaining the purpose of each constraint Benefits: - Prevents using value-type State (wouldn't support mutation) - Prevents using non-Sendable Actions (could cause data races) - Ensures consistency with Feature protocol requirements - Compile-time enforcement of concurrency safety This is a non-breaking change as all existing usage already satisfies these constraints through Feature protocol conformance. All tests pass (255 tests). SwiftLint clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Sources/Flow/ActionHandler/ActionHandler.swift | 12 +++++++++++- Sources/Flow/ActionHandler/ActionProcessor.swift | 11 +++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Sources/Flow/ActionHandler/ActionHandler.swift b/Sources/Flow/ActionHandler/ActionHandler.swift index cd4e3c1..5305e3b 100644 --- a/Sources/Flow/ActionHandler/ActionHandler.swift +++ b/Sources/Flow/ActionHandler/ActionHandler.swift @@ -119,7 +119,17 @@ import Foundation /// /// The Facade pattern here is a feature, not a code smell. It provides clean abstraction /// and hides implementation complexity from users while maintaining full testability. -public final class ActionHandler { +/// +/// ## Type Constraints +/// +/// Type parameters are constrained to match Feature protocol requirements: +/// - `Action: Sendable` ensures safe concurrent action dispatching +/// - `State: AnyObject` ensures reference semantics for direct state mutation +/// - `ActionResult: Sendable` ensures safe concurrent result handling +/// +/// These constraints prevent common errors like using value-type State (which wouldn't +/// support mutation) or non-Sendable actions (which could cause data races). +public final class ActionHandler { private let processor: ActionProcessor /// Creates a ActionHandler with the given action processing logic. diff --git a/Sources/Flow/ActionHandler/ActionProcessor.swift b/Sources/Flow/ActionHandler/ActionProcessor.swift index b89795c..645c840 100644 --- a/Sources/Flow/ActionHandler/ActionProcessor.swift +++ b/Sources/Flow/ActionHandler/ActionProcessor.swift @@ -1,7 +1,9 @@ import Foundation /// Action execution closure that mutates state and returns a task. -public typealias ActionExecution = +/// +/// - Note: Type constraints match Feature protocol requirements to ensure consistency. +public typealias ActionExecution = @MainActor (Action, State) async -> ActionTask @@ -25,7 +27,12 @@ public typealias StateErrorHandler = (Error, State) -> Void /// .use(LoggingMiddleware()) /// .onError { error, state in state.errorMessage = "\(error)" } /// ``` -public final class ActionProcessor { +/// +/// - Note: Type constraints match Feature protocol requirements: +/// - `Action: Sendable` for safe concurrency across tasks +/// - `State: AnyObject` ensures reference semantics for state mutation +/// - `ActionResult: Sendable` for safe concurrency of operation results +public final class ActionProcessor { private let baseExecution: ActionExecution private let errorHandler: StateErrorHandler? private let middlewareManager: MiddlewareManager