ExpressibleByStringLiteral with optionals in function parameters

Viewed 281

Consider the following enum

enum Text: Equatable {
    case plain(String)
    case attributed(NSAttributedString)
}

I've made it conform to ExpressibleByStringLiteral

extension Text: ExpressibleByStringLiteral {
    public typealias StringLiteralType = String
    
    public init(stringLiteral value: StringLiteralType) {
        self = .plain(value)
    }
}

With all this, I can do the following, just like I would expect:

let text: Text = "Hello" // .plain("Hello")
let text2: Text? = "Hello" // .plain("Hello")

But I get compiler errors for the following:

let nilString: String? = nil
let text3: Text? = nilString // Cannot convert value of type 'String?' to expected argument type 'Text?'

func foo(text: Text?) { /** foo **/ }
let text = "Hello"
foo(text: text) // Cannot convert value of type 'String' to expected argument type 'Text?'

func bar(text: Text?) { /** bar **/ }
bar(text: nilString) // Cannot convert value of type 'String?' to expected argument type 'Text?'

How can I get those to work ?

I've also tried to extend Optional: ExpressibleByStringLiteral where Wrapped: ExpressibleByStringLiteral, but that didn't help.

1 Answers

ExpressibleByStringLiteral is not about automatic casting(String, Int) to your custom type. Literal is exactly "word" (string literal) or 12.63 (Double literal). But in your example let text = "Hello" constant text has type String. But method foo expect type Text? for argument.

But you can use it like

foo(text: "Some text")

Now compiler know that it can convert your String literal to Text. And then wrap it into Optional<Text>.

Related