SwiftUI previews type lookup

Does anybody know how type lookup in SwiftUI previews is different from standard Swift type lookup? Whenever I have a type that shadows one of the SwiftUI types, e.g. a type named Color, and I use that type as a generic parameter, I get an error saying that the type ”is ambiguous for type lookup in this context”, even though the code builds correctly in debug and release.

(I'm aware that I can prefix the type name with the module name to resolve the ambiguity. What I’m asking is: why is there even an ambiguity in the first place?)

The following code illustrates the issue:

// ContentView.swift

import SwiftUI

struct ContentView<T>: View where T: CustomStringConvertible {
    let value: T

    var body: some View {
            .frame(maxWidth: .infinity, maxHeight: .infinity)

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView<Color>(value: Color())

Must be in a separate file in the same project:

// Color.swift

struct Color: CustomStringConvertible {
    var description: String { "Color" }

My WAG from things I've read or heard on podcasts: In preview mode your views (perhaps whole app) are built as a type of dynamic library which is then injected into the preview app running on a special background simulator. This enables "runtime" code replacement in the preview as you change your code. However, due to this, you may encounter issues like those you describe here, as the special type shadowing behavior you get proper targets (where your types can shadow imported types without errors) isn't available in the special mode they build the previews with. They either need to add functionality to the compiler to enable this behavior even in the preview builds, or use the current build artifacts to build the previews. Who knows which is easier or more likely.

Do you have links to any of those blogs/tweets or podcasts?

Since there’s no ambiguity if the shadowing type is defined in the same file as the preview, it seems like it’s only the current file being that’s built as it’s own module, not the whole app. But that’s just another wild guess.

Terms of Service

Privacy Policy

Cookie Policy