Swift Check Type Against a Generic Type

Swift check type against a generic type

You cannot tell a function what the types of its generic placeholders are (unlike with a generic struct). It must infer them from the context e.g. its arguments.

One way to do what you want is to add another argument related to type T. Rather than pass in a dummy value, you could use the metatype of the type you want:

func generic<T>(parameter: AnyObject, type: T.Type) -> Bool {
if parameter is T {
return true
} else {
return false
}
}

let o: AnyObject = "hello"
generic(o, String.self) // true
generic(o, NSString.self) // also true
generic(o, Int.self) // false

However, I would ask you, what is it you think you're achieving here? You've essentially done nothing more than implement is as a function:

o is String     // true
o is NSString // true
o is Int // false

The point of generics is to operate on arguments generically, but you aren't giving the function any argument of a specific type to actually do any work on (hence the inability to infer one).

Use Swift `is` to check type of generic type

Here's 2 things that might work for you.

Option 1:

Note that child is a tuple containing a String? with the name of the property ("property" in your example) and the item. So you need to look at child.1.

In this case, you should be checking:

if String(describing: type(of: child.1)).hasPrefix("Foo<")

Option 2:

If you create a protocol FooProtocol that is implemented by Foo<T>, you could check if child.1 is FooProtocol:

protocol FooProtocol { }

struct Foo<T>: FooProtocol {}

struct Bar {
var property = Foo<String>()
}

var test = Bar()

let mirror = Mirror(reflecting: test)

// This code is trying to count the number of properties of type Foo
var inputCount = 0
for child in mirror.children {
if child.1 is FooProtocol {
inputCount += 1
}
}

Swift - checking type of a generic class

One of the solutions can be to use a protocol for your generic List:

protocol AnyList {}

class List<T>: AnyList {
var value: T
var next: List<T>?
...
}

func isList<T>(_ object: T) -> Bool {
object is AnyList
}

let a = List<Int>(value: 2)
let b = "something which is not a list"

print(isList(a)) // true
print(isList(b)) // false

Check type of generic class without respecting generic type constraint

It is hard to express how complicated the world gets once you start allowing non-final subclasses. If you can possibly make these final classes or protocols, many little sharp edges will go away.

What you say you want and the code you're writing don't really line up (which is very common when dealing with subclasses). So it matters what you really want.

I would like to check if param has a class of type B as a generic constraint.

Sure. That's easy.

class B : SomeInterface {
func someFunc(param: C) {
if let typed = param as? A<B> {
print(typed)
} else {
print("NO")
}
}
}

This will work anytime we get an A<B>. It will not work if we receive A<SubClassOfB>, even if that's passed to SubclassOfB.someFunc(). (See what I meant about it being subtle?)

From your code, you seem to actually want "if I'm passed A<Self>" where "Self" means "exactly my class, not a superclass or subclass." The only way I've ever seen that done is with a protocol extension:

extension SomeInterface {
func someFunc(param: C) {
if let typed = param as? A<Self> {
print(typed)
} else {
print("NO")
}
}
}

This allows Self to be replaced with "my class." But note that this means someFunc(A<MySubclass>) won't work. A<Self> is not the same thing as A<Subclass>. Note that you can add a where clause to the extension to limit its scope:

extension SomeInterface where Self: B { ... }

If you mean "T is either Self or some subclass of Self", maybe it's possible, but in my experience it gets more and more tricky and fragile. You can't make generic types covariant on their parameters in Swift, so A<Subclass> is not itself a subtype of A<Superclass> (that's a much trickier problem than it sounds like, and you wouldn't always want it to be true). This is the kind of crazy corner case that goes away if you'll just mark B as final. Then most of the rat's nest goes away.

Type checking with generics and raw types?

This doesn't work because Swift wants to know the type of the generic. If you just want to access a property without dealing with the generic, you can extract that to a protocol.

protocol SomethingThatHasFoo {
var foo: String { get }
}

class SomeViewController<T>: UIViewController, SomethingThatHasFoo {
let foo = "foo"
}

class AnotherViewController {
private weak var someVC: UIViewController?

func someFunc() {
if let vc = someVC as? SomethingThatHasFoo {
print(vc.foo)
}
}
}


Related Topics



Leave a reply



Submit