🏷️

[Tagged]SwiftのモデルにIDを作る[幽霊型]

2023/11/13に公開

Tagged

https://github.com/pointfreeco/swift-tagged

Taggedで解決できる問題

以下のコードは一見何も問題がないように思えますが、fetchUserのidにはStringであれば何でも渡せてしまいます。

呼び出しを間違えても、コンパイルエラーにはならないため、気づかない可能性があります。

struct User: Identifiable {
  typealias ID = String
  let id: ID
  let name: String
  let age: Int
}

func fetchUser(id: User.ID) -> User

let id = book.id
let user = fetchUser(id: id) // 型は同じだがデータが異なる

Taggedを使った解決方法

typealias ID = Tagged<Self, String>を宣言します。

import Tagged

struct User: Identifiable {
  typealias ID = Tagged<Self, String>
  let id: ID
  let name: String
  let age: Int
}

func fetchUser(id: User.ID) -> User

これにより以下のコードは型が異なるため、コンパイルエラーになり間違いに気づきやすくなります。

let id = map.id
let user = fetchUser(id: id)

Taggedを使わない自前解決方法

モデルに対してネストしたIDを宣言することで型が被らないようにすることができます。
ただ全モデルにIDを作らないといけません。

struct User: Identifiable {
  let id: ID
  let name: String
  let age: Int
  
  struct ID: Hashable {
    var value: String
  }
}

Discussion