Generic constraint with not equals

You can do:

protocol SomeView {
    associatedtype ViewModel
}

private function foo<T: SomeView>(view: T) where T.ViewModel == Void {

}

But it's not possible to do:

private function foo<T: SomeView>(view: T, viewModel: T.ViewModel) where T.ViewModel != Void {
     
}

It seems like it's possible to constraint a type to being another type. Then it should be possible to do the opposite. A type is either a type or not, there's no in-between.

or is there some other way of deciding which method can be called based on a type constraint?

The problem with negative constraints is that they don't allow you to write any useful generic algorithms. They tell you what a type isn't or can't do, and nothing about what it is or can do (which is what you actually need to know).

You can absolutely add constraints on associated types, though - either at the protocol level or at the algorithm level:

// protocol-level constraint:

protocol ViewModelProtocol {
  associatedtype Element
}
protocol SomeView {
  associatedtype ViewModel: ViewModelProtocol where ViewModel.Element: Hashable
}

// algorithm-level constraint:

protocol SomeView {
  associatedtype ViewModel
}
func doSomething<T>(with view: T) where T: SomeView, T.ViewModel: ViewModelProtocol, T.ViewModel.Element: Hashable {
 // ...
}