KeyPath Basics
Reference properties as first-class values.
KeyPath Basics is a free Swift Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Is a Key Path?
A key path is a value that describes a path to a property without actually accessing it. Think of it as a stored, reusable reference to which property you want, separate from which instance you read it from.
You write a key path with a backslash, the type name, a dot, and the property name. Swift gives this expression a KeyPath value that you can pass around like any other value.
struct Person {
let name: String
let age: Int
}
let nameKeyPath = \Person.name
print(type(of: nameKeyPath))Reading a Value
To read a property through a key path, use the [keyPath:] subscript on an instance. You pass the key path inside the brackets and Swift returns the value at that path.
This is the runtime counterpart to writing the property name directly, but now the property is chosen by data rather than hard-coded.
struct Person {
let name: String
let age: Int
}
let alice = Person(name: "Alice", age: 30)
let path = \Person.name
print(alice[keyPath: path])Key Path Syntax in Detail
The general form is the backslash escape, then the root type, then a dot, then the property name. The backslash signals to Swift that you want a key path rather than the property's value.
The root type is the type the path starts from. The result type is the type of the final property. So a path from Person to its age property has root Person and value Int.
struct Person {
let name: String
let age: Int
}
let ageKeyPath: KeyPath<Person, Int> = \Person.age
let bob = Person(name: "Bob", age: 42)
print(bob[keyPath: ageKeyPath])Chaining Through Nested Properties
Key paths can drill into nested values. If a property is itself a struct, you can continue the path with another dot to reach a deeper property.
The whole chain is still a single key path value, and its root and result types reflect the start and end of the chain.
struct Address {
let city: String
}
struct Person {
let name: String
let address: Address
}
let cityPath = \Person.address.city
let carol = Person(name: "Carol", address: Address(city: "Oslo"))
print(carol[keyPath: cityPath])Storing Key Paths in Variables
Because a key path is just a value, you can store it in a variable, return it from a function, or keep a collection of key paths. This lets you decide which property to read at runtime.
Here we pick one of two stored key paths based on a flag.
struct Person {
let name: String
let age: Int
}
let showAge = true
let chosen: PartialKeyPath<Person> = showAge ? \Person.age : \Person.name
let dave = Person(name: "Dave", age: 27)
print(dave[keyPath: chosen])PartialKeyPath and AnyKeyPath
Swift has a small family of key path types. KeyPath<Root, Value> knows both ends. PartialKeyPath<Root> knows the root but erases the value type. AnyKeyPath erases both.
The more type information you keep, the more the compiler can check for you. Reach for the partial or any forms only when you genuinely need to mix paths of different value types.
struct Person {
let name: String
let age: Int
}
let paths: [PartialKeyPath<Person>] = [\.name, \.age]
let eve = Person(name: "Eve", age: 19)
for p in paths {
print(eve[keyPath: p])
}Shorthand Inside a Known Type
When the root type is already known from context, you can drop the type name and write just the backslash, a dot, and the property. The compiler infers the root.
This shorthand keeps call sites short, especially inside collection operations where the element type is obvious.
struct Person {
let name: String
let age: Int
}
func value(of person: Person, at path: KeyPath<Person, Int>) -> Int {
person[keyPath: path]
}
let frank = Person(name: "Frank", age: 55)
print(value(of: frank, at: \.age))Key Paths as Function Arguments
A common pattern is a generic function that accepts a key path and applies it to many instances. This decouples what you read from the logic that does the reading.
Here a generic helper extracts any property of any type from a list of people.
struct Person {
let name: String
let age: Int
}
func extract<T>(_ people: [Person], _ path: KeyPath<Person, T>) -> [T] {
people.map { $0[keyPath: path] }
}
let people = [Person(name: "Ana", age: 21), Person(name: "Ben", age: 34)]
print(extract(people, \.name))
print(extract(people, \.age))Key Paths and Computed Properties
Read-only key paths work with computed properties too. The path captures the computation, so reading through it runs the getter.
This means a key path is not limited to stored properties; any readable property qualifies.
struct Rectangle {
let width: Double
let height: Double
var area: Double { width * height }
}
let areaPath = \Rectangle.area
let r = Rectangle(width: 3, height: 4)
print(r[keyPath: areaPath])Identity Key Path
There is a special key path that refers to the whole value itself, written as a lone backslash followed by a dot and self. Reading through it returns the instance unchanged.
It is handy when an API expects a key path but you want the element as-is, such as sorting numbers by themselves.
let numbers = [3, 1, 2]
let identity = \Int.self
for n in numbers {
print(n[keyPath: identity])
}Comparing Key Paths
Key paths are Hashable and Equatable. Two key paths that point to the same property of the same type are equal, so you can store them in sets or use them as dictionary keys.
This is useful for building tables that map a property to a label or formatter.
struct Person {
let name: String
let age: Int
}
let labels: [PartialKeyPath<Person>: String] = [
\Person.name: "Full Name",
\Person.age: "Years Old"
]
print(labels[\Person.age] ?? "unknown")Quick Check: Reading via Key Path
Test your understanding of how to read a property through a key path.
Recap: Key Path Basics
You learned the foundations of key paths:
- A key path is written with a backslash, the root type, a dot, and a property name, and it describes a property without reading it.
- Read a value using the
[keyPath:]subscript on an instance. - Paths can chain into nested properties and target computed properties.
KeyPath,PartialKeyPath, andAnyKeyPathtrade type safety for flexibility.- Key paths are values: store them, pass them, compare them, and use them as dictionary keys.
Next you will use key paths to make collection operations far more concise.
struct Person {
let name: String
let age: Int
}
let path = \Person.age
let gina = Person(name: "Gina", age: 48)
print("Read via key path: \(gina[keyPath: path])")Frequently asked questions
Is the “KeyPath Basics” lesson free?
Yes — the full text of “KeyPath Basics” is free to read here on the web, and the Swift Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Swift Academy course, upgrade to CoddyKit PRO.
What will I learn in “KeyPath Basics”?
Reference properties as first-class values. You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Swift Academy?
No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “KeyPath Basics” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Swift Academy lesson?
Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.