So far in this series, Swift has been quietly figuring out what type of data we're working with — and it's been doing a great job. But sometimes you need to take the wheel and tell Swift exactly what type you want. That's where type annotations come in.
🧠 Type Inference — Swift's Default Behaviour
When you write this:
let characterName = "Itachi"
var killCount = 0
Swift looks at the values and makes a smart guess:
-
"Itachi"→ must be aString -
0→ must be anInt
This is called type inference — Swift infers the type from the value you assign. Most of the time this works perfectly and you don't need to do anything extra.
✍️ Type Annotations — Being Explicit
Type annotations let you tell Swift directly what type a variable or constant should be, using a colon after the name:
let characterName: String = "Itachi"
var killCount: Int = 0
Both of these do the same thing as before — but now you're the one specifying the type, not Swift. That's the key difference.
🤔 So Why Would You Ever Need This?
There are three main situations where type annotations become useful:
1️⃣ Swift can't figure out the type itself
This usually happens with more advanced code — like when you're loading data from an API or doing something complex where Swift doesn't have enough context to make a decision on its own. You step in and tell it.
2️⃣ You want a different type than Swift's default
This is the most common beginner use case. Consider this:
var powerLevel = 0
Swift sees 0 and assumes Int. But what if power levels in your app can be 99.5? You'd need a Double. Without a type annotation, you'd have to write:
var powerLevel = 0.0
Which works, but with a type annotation it reads much more clearly:
var powerLevel: Double = 0
Now powerLevel is definitely a Double — even though the starting value looks like a whole number. Much more intentional and readable ✅
3️⃣ You want to declare a variable without giving it a value yet
Sometimes you know a variable is coming, but you don't have the value for it just yet. Type annotations make this possible:
var winnerName: String
// ... lots of battle logic ...
winnerName = "Levi Ackerman"
print(winnerName)
Swift is totally fine with this — as long as you provide the value before you use the variable. If you forget to assign it before using it, Swift will refuse to compile. And if you try to change it to a different type later, Swift will also refuse. Safe on all sides. 🔒
📚 Type Annotations for Every Swift Type
Here's a handy reference for all the types we've covered in this series, with their type annotation syntax:
| Type | Annotation | Example |
|---|---|---|
| Text | String |
let name: String = "Gojo" |
| Whole number | Int |
var level: Int = 1 |
| Decimal number | Double |
let height: Double = 1.93 |
| True / False | Bool |
var isAlive: Bool = true |
| Array of strings | [String] |
var moves: [String] = ["Rasengan"] |
| Dictionary | [String: Int] |
var scores: [String: Int] = [:] |
| Set of strings | Set<String> |
var titles: Set<String> = [] |
🏗️ Creating Empty Collections with Type Annotations
This is where type annotations become truly necessary — when you want to start with an empty collection and fill it in over time.
If you try to create an empty array without a type annotation, Swift has no idea what kind of data it will hold:
var jutsuList = [] // ❌ Swift doesn't know what type this is
You need to tell it:
var jutsuList: [String] = []
Or using Swift's shorthand:
var jutsuList = [String]()
Both are valid — pick whichever feels more readable to you.
Here's a real example of why you'd want to start empty. Say you have a list of all ninja in a village, and you want to filter out just the ones in Squad 7:
let allNinja = ["Naruto", "Sasuke", "Sakura", "Kakashi", "Sai", "Yamato"]
var squadSeven: [String] = [] // Start empty
for ninja in allNinja {
if ninja == "Naruto" || ninja == "Sasuke" || ninja == "Sakura" {
squadSeven.append(ninja)
}
}
print(squadSeven)
// ["Naruto", "Sasuke", "Sakura"]
You didn't know which names would make the cut ahead of time — so you started empty and built it up as you went. This pattern shows up constantly in real apps. 💡
The same idea applies to dictionaries and sets:
var characterStats: [String: Int] = [:] // Empty dictionary
var uniqueAbilities: Set<String> = [] // Empty set
⚖️ Type Inference vs Type Annotation — Which Should You Use?
Honestly? This comes down to personal style. Here's how to think about it:
| Situation | Recommended approach |
|---|---|
| You have an initial value and Swift guesses correctly | ✅ Use type inference — keep it short |
| You want a different type than Swift's default | ✅ Use type annotation |
| You don't have a value yet | ✅ Must use type annotation |
| Your team has a strict style guide | Follow the guide |
In practice, most Swift developers prefer type inference wherever possible — it keeps code shorter and easier to read. But knowing type annotations cold is essential, because you will need them.
⛔ One Hard Rule — Types Can Never Change
No matter which approach you choose, Swift has one rule that never bends:
A variable's type is set once and never changes.
This means you can't do this:
var chakraLevel = 100 // Swift infers Int
chakraLevel = "Maximum" // ❌ ERROR — can't assign a String to an Int
And you can't trick it with annotations either:
let score: Int = "Zero" // ❌ ERROR — "Zero" is not an Int, period
Swift just can't convert "Zero" to an integer, no matter what annotation you use. The annotation has to be truthful about the type you're actually storing. This is what makes Swift a type-safe language — it stops nonsense like adding a number to a boolean (5 + true) before your app even runs. 🛡️
🧩 Putting It All Together
Here's a mini character builder showing type annotations in action:
// Using type annotations explicitly
let heroName: String = "Naruto Uzumaki"
var currentRank: String = "Genin"
var chakra: Double = 100.0
var isHokage: Bool = false
var knownJutsu: [String] = []
var stats: [String: Int] = [:]
// Fill things in
knownJutsu.append("Shadow Clone Jutsu")
knownJutsu.append("Rasengan")
knownJutsu.append("Sage Mode")
stats["speed"] = 90
stats["strength"] = 85
stats["intelligence"] = 70
// Years later...
isHokage = true
currentRank = "Hokage"
print("\(heroName) is now \(currentRank)!")
print("Jutsu count: \(knownJutsu.count)")
print("Is Hokage: \(isHokage)")
Output:
Naruto Uzumaki is now Hokage!
Jutsu count: 3
Is Hokage: true
🌟 Wrap Up
Type annotations are Swift's way of letting you be explicit about what your variables hold. Here's what to remember:
- Type inference — Swift figures out the type from the value you give it. Clean and short.
-
Type annotation — You tell Swift the type with
: TypeName. Explicit and intentional. - Use annotations when Swift guesses wrong, when you need an empty collection, or when you're declaring a variable without a value yet.
- A variable's type is set once and never changes — that's Swift's type safety in action.
- Both approaches are valid — use whichever makes your code clearer in the moment.
Mastering types is one of the foundational skills in Swift — everything else you'll build on top of this. 💪
Top comments (0)