Swiftpack.co - Package - pointfreeco/swift-tagged

🏷 Tagged

MacOS CircleCI Linux Build Status

A library for safer types.


We often work with types that are far too general or hold far too many values than what is necessary for our domain. Sometimes we just want to differentiate between two seemingly equivalent values at the type level.

For example, an email address is nothing but a String, but it should be restricted in the ways in which it can be used. And while a User id may be represented with an Int, it should be distinguishable from an Int-based Subscription id.


Tagged lets us wrap basic types in more specific contexts with ease. Given the following JSON representing a user:

  "id": 1,
  "email": "blob@pointfree.co",
  "subscriptionId": 1

We may be tempted to model it simply:

struct User: Decodable {
  let id: Int
  let email: String
  let subscriptionId: Int?

struct Subscription: Decodable {
  let id: Int

It's easy to model user and subscription ids using the same type, but our app logic shouldn't treat these values interchangeably: doing so could lead to runtime bugs and security issues!

Luckily, we can use Tagged to differentiate these types.

import Tagged

struct User: Decodable {
  typealias Id = Tagged<User, Int>

  let id: Id
  let email: String
  let subscriptionId: Subscription.Id?

struct Subscription: Decodable {
  typealias Id = Tagged<Subscription, Int>

  let id: Id

Now there's no chance we'll accidentally pass a User id where we expect a Subscription id.

Tagged depends on a generic "tag" parameter to make each type unique. In these cases, we use the parent type to tag each Id type.

What if there's no parent type? Let's say we want to constrain an Email type that wraps a string.

typealias Email = Tagged<_, String>

We can tag Email by defining an uninhabited EmailTag enum.

enum EmailTag {}
typealias Email = Tagged<EmailTag, String>

Now our User can be even more type-safe.

struct User: Decodable {
  typealias Id = Tagged<User, Int>

  let id: Id
  let email: Email
  let subscriptionId: Subscription.Id?

Tagged relies on conditional conformance to be practical: if the raw values are encodable or decodable, equatable, hashable, or comparable, the tagged values follow suit.

Tagged types also inherit any literal expressibility. Our User type above can be instantiated simply using the underlying literals.

  id: 1,
  email: "blob@pointfree.co",
  subscriptionId: 1



If you use Carthage, you can add the following dependency to your Cartfile:

github "pointfreeco/swift-tagged" ~> 0.1


If your project uses CocoaPods, just add the following to your Podfile:

pod 'Tagged', '~> 0.1'


If you want to use Tagged in a project that uses SwiftPM, it's as simple as adding a dependencies clause to your Package.swift:

dependencies: [
  .package(url: "https://github.com/pointfreeco/swift-tagged.git", from: "0.1.0")

Xcode Sub-project

Submodule, clone, or download Tagged, and drag Tagged.xcodeproj into your project.

Interested in learning more?

These concepts (and more) are explored thoroughly in Point-Free.


All modules are released under the MIT license. See LICENSE for details.


Stars: 165
Help us keep the lights on


Used By

Total: 1


0.1.0 - Apr 16, 2018

This preliminary release has the basic Tagged type implemented with a few starting conformances to common Swift protocols.