PC パソコン

How to Fix “Type of Expression Is Ambiguous Without a Type Annotation” in Swift

When building Swift code in Xcode, you may encounter:

Type of expression is ambiguous without a type annotation

This error means that the Swift compiler cannot determine one unambiguous type for an expression.

Swift performs extensive type inference, so most variables and expressions do not need explicit type declarations. However, inference can fail when several overloads are possible, a closure’s parameter or return type is unclear, a generic parameter has insufficient context, or a collection does not provide enough information about its element type.

The most reliable fix is not to add random casts. Instead, break the expression into smaller pieces and add explicit type information at the point where the compiler no longer has enough context.

  1. What does “Type of expression is ambiguous without a type annotation” mean?
  2. Typical situations where this error appears
  3. Common causes
    1. 1. An empty array has no element type
    2. 2. An empty dictionary has no key or value type
    3. 3. nil does not identify its wrapped optional type
    4. 4. A closure parameter cannot be inferred
    5. 5. A closure return type is ambiguous
    6. 6. Multiple overloads match the expression
    7. 7. A generic parameter cannot be inferred
    8. 8. Result does not have enough generic context
    9. 9. A numeric literal has several possible types
    10. 10. A ternary expression returns different types
    11. 11. A dictionary contains unrelated value types
    12. 12. Optional transformations are too complex
    13. 13. A SwiftUI view expression is very complex
    14. 14. A method chain is too large to diagnose easily
    15. 15. Another call-site error prevents overload resolution
  4. Solution 1: Add an explicit variable type
  5. Solution 2: Add dictionary key and value types
  6. Solution 3: Give nil an optional type
  7. Solution 4: Specify a closure parameter type
  8. Solution 5: Specify a closure return type
  9. Solution 6: Use compactMap when filtering nil results
  10. Solution 7: Specify the result type of a generic function
  11. Solution 8: Disambiguate overloaded functions with argument types
  12. Solution 9: Add types to numeric literals when needed
  13. Solution 10: Make both ternary branches the same type
  14. Solution 11: Model heterogeneous data explicitly
  15. Solution 12: Break a complex expression into smaller statements
  16. Solution 13: Add type annotations between method-chain stages
  17. Solution 14: Specify the result type of map
  18. Solution 15: Specify reduce accumulator types
  19. Solution 16: Specify Result generic types
  20. Solution 17: Give enum cases an explicit type context
  21. Solution 18: Simplify optional map and flatMap chains
  22. Solution 19: Add a function type when storing an overloaded function
  23. Solution 20: Give a closure variable an explicit function type
  24. Solution 21: Make JSON decoding types explicit
  25. Solution 22: Check async function result types
  26. Solution 23: Split complex SwiftUI views into smaller views
  27. Solution 24: Check ForEach element and ID types
  28. Solution 25: Simplify conditional SwiftUI content
  29. Solution 26: Look for an earlier compiler error
  30. Solution 27: Disambiguate overloaded initializers
  31. Solution 28: Give generic collections concrete types
  32. Solution 29: Prefer concrete models over widespread Any usage
  33. Solution 30: Fully decompose a large expression when necessary
  34. If the error occurs in SwiftUI
  35. If the error occurs in map
  36. If the error occurs in reduce
  37. If the error occurs with a dictionary
  38. If the error occurs with nil
  39. If the error occurs with a generic function
  40. Why the highlighted line may not be the real problem
  41. What you should avoid
  42. Fast troubleshooting checklist
  43. Summary

What does “Type of expression is ambiguous without a type annotation” mean?

Swift can normally infer types:

let name = "Alice" let count = 10 let enabled = true

The compiler infers String, Int, and Bool automatically.

When multiple types remain possible and surrounding code does not provide enough context, Swift may report:

Type of expression is ambiguous without a type annotation

Typical situations where this error appears

  • Creating an empty array or dictionary
  • Assigning nil without an expected optional type
  • Using closures whose parameter types cannot be inferred
  • Using map, compactMap, or reduce with unclear return types
  • Calling overloaded functions
  • Using generic functions without enough type context
  • Building complex SwiftUI view expressions
  • Combining optionals and generics
  • Using Result without explicit generic types
  • Using numeric literals in generic contexts
  • Creating dictionaries with mixed value types
  • Writing very long method chains

Common causes

1. An empty array has no element type

let items = []

The compiler does not know whether this should be an array of String, Int, User, or another type.

2. An empty dictionary has no key or value type

let values = [:]

3. nil does not identify its wrapped optional type

let value = nil

This could be String?, Int?, User?, or any other optional type.

4. A closure parameter cannot be inferred

someFunction { value in ... }

If the surrounding generic or overload context is unclear, Swift may not know the type of value.

5. A closure return type is ambiguous

Different branches may return incompatible or unclear values.

6. Multiple overloads match the expression

An overloaded function can leave the compiler unable to select one candidate.

7. A generic parameter cannot be inferred

func makeValue<T>() -> T { fatalError() }

let value = makeValue()

Nothing tells Swift what T should be.

8. Result does not have enough generic context

Result requires both a Success and Failure type.

9. A numeric literal has several possible types

Integer and floating-point literals can represent different concrete numeric types depending on context.

10. A ternary expression returns different types

let value = condition ? 10 : "10"

One branch is Int and the other is String.

11. A dictionary contains unrelated value types

let data = [ "name": "Alice", "age": 20 ]

The intended common value type may not be obvious or desirable.

12. Optional transformations are too complex

Long chains involving optional mapping, generic methods, and nested closures can make inference difficult.

13. A SwiftUI view expression is very complex

View builders generate deeply nested generic types, so a small error inside a large body can produce a broad ambiguity diagnostic.

14. A method chain is too large to diagnose easily

let result = values .filter { ... } .map { ... } .compactMap { ... } .sorted { ... } .reduce(...) { ... }

15. Another call-site error prevents overload resolution

An incorrect argument label, missing argument, wrong property name, or optional mismatch can prevent Swift from selecting a valid overload and produce an ambiguity error.

Solution 1: Add an explicit variable type

Ambiguous:

let items = []

Fixed:

let items: [String] = []

Or:

let items: [Int] = []

Solution 2: Add dictionary key and value types

let values: [String: Int] = [:]

Solution 3: Give nil an optional type

Ambiguous:

let selectedUser = nil

Fixed:

let selectedUser: User? = nil

Solution 4: Specify a closure parameter type

items.map { (item: User) in item.name }

Solution 5: Specify a closure return type

let names = users.map { user -> String in return user.name }

Solution 6: Use compactMap when filtering nil results

let names: [String] = users.compactMap { user in guard user.isEnabled else { return nil }
return user.name

}

This also makes the intended output type easier to understand.

Solution 7: Specify the result type of a generic function

func makeValue<T>() -> T { fatalError() }

let value: String = makeValue()

Now Swift can infer that T is String.

Solution 8: Disambiguate overloaded functions with argument types

func convert(_ value: Int) -> String { String(value) }

func convert(_ value: Double) -> String {
String(value)
}

let number: Int = 10
let text = convert(number)

Solution 9: Add types to numeric literals when needed

let value: Double = 10 let ratio: Float = 0.5

Solution 10: Make both ternary branches the same type

let value: String = condition ? "10" : "20"

Or:

let value: Int = condition ? 10 : 20

Solution 11: Model heterogeneous data explicitly

You can write:

let data: [String: Any] = [ "name": "Alice", "age": 20 ]

Note: Do not use Any only to silence the compiler. A dedicated model usually provides better type safety.

For example:

struct User { let name: String let age: Int }

Solution 12: Break a complex expression into smaller statements

Instead of:

let result = users.filter { $0.isEnabled }.map { $0.name }.sorted().joined(separator: ", ")

write:

let enabledUsers: [User] = users.filter { user in user.isEnabled }

let names: [String] = enabledUsers.map { user in
user.name
}

let sortedNames: [String] = names.sorted()

let result: String = sortedNames.joined(separator: ", ")

This makes the failing inference step much easier to identify.

Solution 13: Add type annotations between method-chain stages

let filtered: [User] = users.filter { $0.isEnabled } let names: [String] = filtered.map { $0.name }

You do not need to annotate every variable. Add types only where the compiler needs more context.

Solution 14: Specify the result type of map

let ids: [Int] = users.map { user in user.id }

Solution 15: Specify reduce accumulator types

let total: Int = numbers.reduce(0) { (result: Int, value: Int) -> Int in
result + value

}

Solution 16: Specify Result generic types

enum NetworkError: Error { case failed }

let result: Result = .success("OK")

Solution 17: Give enum cases an explicit type context

enum Status { case loading case finished }

let status: Status = .loading

Solution 18: Simplify optional map and flatMap chains

let name: String? = user?.name

let trimmedName: String? = name?.trimmingCharacters(
in: .whitespacesAndNewlines
)

Breaking optional transformations into steps makes both the code and compiler diagnostics clearer.

Solution 19: Add a function type when storing an overloaded function

func process(_ value: Int) { }

func process(_ value: String) {
}

let handler: (Int) -> Void = process

Solution 20: Give a closure variable an explicit function type

let completion: (Result<String, Error>) -> Void = { result in switch result { case .success(let value): print(value)
case .failure(let error):
    print(error)
}

}

Solution 21: Make JSON decoding types explicit

struct User: Codable { let name: String }

let user: User = try JSONDecoder().decode(
User.self,
from: data
)

Solution 22: Check async function result types

func fetchUser() async throws -> User { ... }

let user: User = try await fetchUser()

Solution 23: Split complex SwiftUI views into smaller views

var body: some View { VStack { headerView contentView footerView } }

For example:

private var headerView: some View { Text("Header") }

This reduces the size of the generic expression Swift needs to infer at once.

Solution 24: Check ForEach element and ID types

ForEach(users, id: \.id) { user in Text(user.name) }

Make sure the collection element and ID types satisfy the overload you are trying to use.

A different SwiftUI error inside ForEach can sometimes cause the surrounding expression to be reported as ambiguous.

Solution 25: Simplify conditional SwiftUI content

var body: some View { Group { if isLoggedIn { LoggedInView() } else { LoginView() } } }

Extract complex branches into separate views when the diagnostic covers a large part of body.

Solution 26: Look for an earlier compiler error

An ambiguity error can be a secondary symptom.

Check for:

  • Incorrect argument labels
  • Missing arguments
  • Incorrect property names
  • Optional mismatches
  • Wrong generic constraints

Fix the earliest meaningful compiler diagnostic first.

Solution 27: Disambiguate overloaded initializers

When several initializers are possible, give the result an explicit type:

let value: SomeType = SomeType(...)

Solution 28: Give generic collections concrete types

let users: Array<User> = []

Or:

let users: [User] = []

Solution 29: Prefer concrete models over widespread Any usage

Instead of passing unstructured values through:

[String: Any]

prefer a model when possible:

struct APIResponse { let name: String let count: Int }

Solution 30: Fully decompose a large expression when necessary

Instead of:

let result = apiResponse?.users .filter { $0.isEnabled } .compactMap { $0.profile?.name } .sorted() .joined(separator: ", ")

break it into:

let users: [User]? = apiResponse?.users

let enabledUsers: [User]? = users?.filter { user in
user.isEnabled
}

let names: [String]? = enabledUsers?.compactMap { user in
user.profile?.name
}

let sortedNames: [String]? = names?.sorted()

let result: String? = sortedNames?.joined(separator: ", ")

This makes it clear exactly which stage lacks sufficient type information.

If the error occurs in SwiftUI

Check these items in order:

  1. Fix any earlier compiler error.
  2. Split a large body into smaller views.
  3. Check ForEach element and ID types.
  4. Check Binding value types.
  5. Check optionals passed into views.
  6. Verify modifier argument types.
  7. Add closure parameter types where necessary.

If the error occurs in map

Use explicit input and output types:

let result: [String] = values.map { (value: Int) -> String in String(value) }

If the error occurs in reduce

Make the accumulator type explicit:

let total: Double = values.reduce(0.0) { (result: Double, value: Double) -> Double in
result + value

}

If the error occurs with a dictionary

For an empty dictionary:

var scores: [String: Int] = [:]

If values naturally have different fields and types, consider a model instead of a heterogeneous dictionary.

If the error occurs with nil

Give the optional a concrete wrapped type:

var selectedUser: User? = nil

A standalone:

let value = nil

does not contain enough information for Swift to determine the optional type.

If the error occurs with a generic function

Provide the expected result type:

let result: User = makeValue()

You can also redesign the generic API so that its type parameters can be inferred from arguments rather than only from the return value.

Why the highlighted line may not be the real problem

Swift’s type checker analyzes entire expressions. A single incorrect argument or return value inside a large expression can prevent the type of the entire expression from being solved.

Therefore, inspect the calls and closures inside the highlighted expression rather than assuming the entire line needs a cast.

What you should avoid

Do not convert everything to Any just to make the ambiguity error disappear.

That removes useful compile-time type safety and often replaces a compiler error with casts and runtime failures later.

Also avoid adding multiple arbitrary casts to a huge expression. Break the expression apart first and identify the exact point where the type information becomes unclear.

Fast troubleshooting checklist

  1. Break the failing expression into smaller variables.
  2. Specify element types for empty arrays and dictionaries.
  3. Specify the optional type when assigning nil.
  4. Add closure parameter types.
  5. Add closure return types.
  6. Check map, compactMap, and reduce result types.
  7. Specify generic function result types.
  8. Check overloaded functions and initializers.
  9. Make ternary branches return compatible types.
  10. Specify numeric literal types when needed.
  11. For SwiftUI, split complex views into smaller components.
  12. Check whether an earlier compiler error is the actual cause.

Summary

“Type of expression is ambiguous without a type annotation” means that Swift does not have enough contextual information to infer one concrete type for an expression.

Common causes include empty collections, nil without an expected optional type, ambiguous closure parameters or return values, generic functions, overloads, complex method chains, and large SwiftUI view expressions.

The most effective fix is to break complex expressions into smaller steps and add explicit type annotations only where the compiler needs more information.

For map, compactMap, reduce, generics, and SwiftUI code in particular, making input and output types explicit is often the fastest way to expose the real source of the ambiguity.