how to use `if case` statement as boolean in swift

case .gem = cookie.type is not a boolean expression, and if statements not only accept boolean expressions. However, in the closure argument for filter, you must write an Bool expression or a block that returns Bool.

One way to do that is:

cookies.filter { 
    if case $0.type = .gem { return true }
    else { return false }
}

Or, you can add convenient properties to CookieType that gives you Bool values, if you tend to do this a lot:

enum CookieType {
  case regular(type: Int)
  case gem(type: GemType)

  var isRegular: Bool {
    if case .regular = self { return true }
    else { return false }
  }

  var isGem: Bool {
    if case .gem = self { return true }
    else { return false }
  }
}

Then you can do:

cookies.filter(\.isGem)

This is what I would do:

// To overcome swift's limitation where we want a boolean expr of whether cookie is of type (ignoring associated value)
enum RawCookieType {
  case regular
  case gem
}

enum CookieType {
  case regular(type: Int)
  case gem(type: GemType)
}

extension CookieType {
  var rawType: RawCookieType {
    switch self {
    case .regular:
      return .regular
    case .gem:
      return .gem
    }
  }
}

Then in the call site, you can do

func cookies(of type: RawCookieType) -> [Cookie] {
  return cookies.filter { $0.type.rawType == type }
}

Normally, if case and switch statements are abstractions based on the pattern matching operator ~=, but that's not how enums with associated types are implemented. As such, for the time being, you need to reverse-engineer how it might have been done, to allow this:

cookies.filter { CookieType.regular ~= $0.type }

I do not believe it is possible to avoid the explicit CookieType there, but it still reads better than all alternatives.

/// Match `enum` cases with associated values, while disregarding the values themselves.
/// - Parameter case: Looks like `Enum.case`.
public func ~= <Enum, AssociatedValue>(
  case: (AssociatedValue) -> Enum,
  instance: Enum
) -> Bool {
  Mirror.associatedValue(of: instance, ifCase: `case`) != nil
}
public extension Mirror {
  /// Get an `enum` case's `associatedValue`.
  static func associatedValue<AssociatedValue>(
    of subject: Any,
    _: AssociatedValue.Type = AssociatedValue.self
  ) -> AssociatedValue? {
    guard let childValue = Self(reflecting: subject).children.first?.value
    else { return nil }

    if let associatedValue = childValue as? AssociatedValue {
      return associatedValue
    }

    let labeledAssociatedValue = Self(reflecting: childValue).children.first
    return labeledAssociatedValue?.value as? AssociatedValue
  }

  /// Get an `enum` case's `associatedValue`.
  /// - Parameter case: Looks like `Enum.case`.
  static func associatedValue<Enum, AssociatedValue>(
    of instance: Enum,
    ifCase case: (AssociatedValue) throws -> Enum
  ) rethrows -> AssociatedValue? {
    try associatedValue(of: instance).filter {
      .equate(try `case`($0), to: instance) {
        Self(reflecting: $0).children.first?.label
      }
    }
  }
}
public extension Optional {
  /// Transform `.some` into `.none`, if a condition fails.
  /// - Parameters:
  ///   - isSome: The condition that will result in `nil`, when evaluated to `false`.
  func filter(_ isSome: (Wrapped) throws -> Bool) rethrows -> Self {
    try flatMap { try isSome($0) ? $0 : nil }
  }
}
public extension Equatable {
  /// Equate two values using a closure.
   static func equate<Wrapped, Equatable: Swift.Equatable>(
    _ optional0: Wrapped?, to optional1: Wrapped?,
    using transform: (Wrapped) throws -> Equatable
  ) rethrows -> Bool {
    try optional0.map(transform) == optional1.map(transform)
  }
}