Bartłomiej Semańczyk
Bartłomiej Semańczyk

Reputation: 61774

How do I define extension for Dictionary of specific type?

I have created typealias:

typealias Multilang = [String: Any]

Now I would like to extend that Dictionary with property localized. Is it possible?

How do I need to use it?

let dictionary: Multilang = ["en": "b", "pl": "d"]()
let value = dictionary.localized

I try to do it like this:

extension Dictionary where Dictionary: Multilang {
    var localized: String {
        print("self: \(self)")
        return "hello"
   }
}

but it doesn't work. Why?

Type 'Dictionary(Key, Value)' constrained to non-protocol, non-class type 'Multilang' (aka 'Dictionary(String, Any)')

Upvotes: 2

Views: 531

Answers (3)

Chris
Chris

Reputation: 4391

For Swift 3 and above you can try this method to extend a dictionary of type [String: Any].

extension Dictionary where Key: ExpressibleByStringLiteral, Value: Any {
    // Your extension code
    var localized: String {
    print("self: \(self)")
    return "hello"
}

ExpressibleByStringLiteral is a protocol that String and StaticString types conform to.

You cannot apply it just to the type alias, because Multilang is just a label for [String:Any], so even if you could extend it, it would extend all dictionaries of this type anyway.

Upvotes: 1

Arkku
Arkku

Reputation: 42139

It is (unfortunately) not possible to use typealias in this way, because it does not create a new type. For example, you can have typealias Foo = [String: Any] and typealias Bar = [String: Any], but Foo and Bar still both the same type.

So either you have to extend all [String: Any] dictionaries, or you need to create a wrapper type (you also cannot subclass Dictionary because it is a struct). For example:

struct Multilang<Element> {
    var dictionary: [String: Element]
    var localized: Element? {
        return dictionary[currentLanguage]
    }
}

The downside is you need to define all the wrapper methods and properties that you want to use through multilang.foo syntax, but if it suffices to have just multilang.localized, you can do all the rest through multilang.dictionary.foo.

You can also implement ExpressibleByDictionaryLiteral to make creating these objects easy:

extension Multilang: ExpressibleByDictionaryLiteral {
    init(dictionaryLiteral elements: (String, Element)...) {
        dictionary = .init(elements) { $1 }
    }
}

let multilang: Multilang = [ "en": "English", "pl": "Polish" ]

Upvotes: 3

Ilya Kharabet
Ilya Kharabet

Reputation: 4621

You can write an extension like this:

extension Dictionary where Key == String, Value == Any {
    var localized: String {
        print("self: \(self)")
        return "hello"
    }
}

or:

extension Dictionary where Dictionary == Multilang

Upvotes: 2

Related Questions