KeyPath in Swift: Syntax.
Tags: swift, mobile, ios, programming
Published: 2023-01-29 06:46:43

**KeyPath** is a type that represent a **references** to **properties** and **subscripts**. Since it is a type, you can store it in a variable, pass it around, or even perform an operation on a key path. We can use a key path to **get/set their underlying values at a later time**.

Let's create a few structs, which we will use as an example.

```swift

// 1
struct User {
    let name: String
    let email: String
    let address: Address?
    let role: Role
}

// 2
struct Address {
    let street: String
}

// 3
enum Role {
    case admin
    case member
    case guest
    
    var permissions: [Permission] {
        switch self {
        case .admin:
            return [.create, .read, .update, .delete]
        case .member:
            return [.create, .read]
        case .guest:
            return [.read]
        }
    }
}

// 4
enum Permission {
    case create
    case read
    case update
    case delete
}
```

1 We declare a `User` struct which stores `name`, `email`, `address`, and `role`.
2 `Address` is a struct that keeps the information about the address. For brevity, we only have a `street` name.
3 We have all possible roles as an enum, `Role`. It also holds a computed property that returns an array of `Permission` that particular have.
4 `Permission` is an enum of all possible actions a user can make.

## Key Path Expression
Key Path expressions have the following form:

```swift
\type name.path
```

## Type Name
The **type name** is the name of a concrete type, including any generic parameters if the types have one.

```swift
// 1
let stringDebugDescription = \String.debugDescription 
// KeyPath

// 2
let userRole = \User.role 
// KeyPath

// 3
let firstIndexInteger = \[Int][0] 
// WritableKeyPath<[Int], Int>

// 4
let firstInteger = \Array.first 
// KeyPath<[Int], Int?>
```

1 Key path which type is a `String`.
2 Key path which type is our custom struct, `User`.
3, 4 We can reference array by the full type name (`Array`) or shortened form (`[]`), but you have to also specify its generic type, `[Int] and Array<Int>`.

Like most things in Swift, type names can be omitted in contexts where type can be inferred.

In the following example, type name can be inferred from the explicit variable type, so we can leave the type name blank. Notice that we still need \ and .

```swift
// \String.debugDescription => \.debugDescription
let stringDebugDescription: KeyPath<String, String> = \.debugDescription
```

## Path
The `path` can be property names, subscripts, optional-chaining expressions, and forced unwrapping expressions. Basically, everything that we usually use when reference value on an instance object/struct.

```swift
// 1 
let userName = \User.name
//  KeyPath

// 2
let firstIndexInteger = \[Int][0]
// WritableKeyPath<[Int], Int>

// 3
let streetAddress = \User.address?.street
// KeyPath

// 4
let forceStreetAddress = \User.address!.street
// KeyPath
```

1 Key path which path is a property name.
2 Key path which path is a subscript.
3 Key path which path is an optional-chaining to a property.
4 Key path which path is forced unwrapping to a property name.

Path can be repeated as many times as needed, and it can also refer to a computed property name.

```swift
let userRolePermissions = \User.role.permissions
// KeyPath<User, [Permission]>

let firstUserRolePermissions = \User.role.permissions[0]
// KeyPath<User, Permission>
```

## Syntax
I think the syntax of a key path should become clearer to you at this point. Since `KeyPath` is a way to define a reference to properties and subscripts, that means it can use any expression we use to reference properties and subscripts from an instance.

To convert a normal reference to a key path, we replace any class/struct instance with a backslash ( `\` ) followed by that instance type.

```swift
let streetValue = user.address?.street
// KeyPath version referencing the same value.
let streetKeyPath = \User.address?.street
```

---

Next Articles: 
- [Types of KeyPath in Swift](https://dev.to/sergeyleschev/types-of-keypath-in-swift-2o6m)
- [KeyPath Usage in Swift](https://dev.to/sergeyleschev/keypath-usage-in-swift-393p)

---

**Contacts**
I have a clear focus on time-to-market and don't prioritize technical debt. And I took part in the Pre-Sale/RFX activity as a System Architect, assessment efforts for Mobile (iOS-Swift, Android-Kotlin), Frontend (React-TypeScript) and Backend (NodeJS-.NET-PHP-Kafka-SQL-NoSQL). And I also formed the work of Pre-Sale as a CTO from Opportunity to Proposal via knowledge transfer to Successful Delivery.

🛩️ #startups #management #cto #swift #typescript #database
📧 Email: sergey.leschev@gmail.com
👋 LinkedIn: https://linkedin.com/in/sergeyleschev/
👋 LeetCode: https://leetcode.com/sergeyleschev/
👋 Twitter: https://twitter.com/sergeyleschev
👋 Github: https://github.com/sergeyleschev
🌎 Website: https://sergeyleschev.github.io
🌎 Reddit: https://reddit.com/user/sergeyleschev
🌎 Quora: https://quora.com/sergey-leschev
🌎 Medium: https://medium.com/@sergeyleschev
🖨️ PDF Design Patterns: [Download](https://sergeyleschev.github.io/sergeyleschev-design-patterns.pdf)