The RawRepresentable protocol

What is it and how to make use of it?

published on February 15, 2025

If you’ve ever used a Swift enum with a raw value, you may not even realise that you have already worked with the RawRepresentable protocol. But what is it and how can you make use of it?

In this article we are going to investigate the RawRepresentable protocol and I’m going to show you some neat ways for using the protocol to our advantage.

Why are we talking about this?

The other day I’ve open sourced a really small package, SecureStore. Basically it’s just a keychain access wrapper for swift that is using the Security framework from apple to read and write the keychain.

One of the convenience features of the package is that you can use any enum with a String raw value as a key for saving or retrieving values from the store like this:

let value = store.retrieve(for: MyEnum.myKey)

The advantages of this may be pretty clear but let’s break them down real quick:

  1. The author of a package may not be able to provide an enum that describes all cases that the user needs. (Like my case with the secure store. You may have any string as a key)
  2. Using an enum prevents bugs like a typo in your string
  3. Of course, a string property on the type using the store can work just as well and there is really nothing wrong with that solution either, I just find it more convenient in many cases to have an enum with all the possible keys

So what about the RawRepresentable protocol?

As the documentation states, RawRepresentable<T> requires the conforming types to be able to convert to and from a raw value of the type T. This means that a type conforming to it will have a property called rawValue and an initialiser with a parameter rawValue of type T. Does that sound familiar?

Exactly, that’s just like an enum with a raw value and guess what.. an enum with a raw value does conform to the raw representable protocol.

Realising this, let’s see how to implement a function that takes any enum case as an argument:

func printRaw(_ value: any RawRepresentable&#x3C;String>) {
	print(“The value is \(value.rawValue)”)
}

And that’s it! Let’s test it

enum TestEnum: String {
	case testCase = “testCase”
}

printRaw(TestEnum.testCase)

As you may have guessed already, the output of the call will be The value is testCase.

But it is generic for a reason!

You are not limited to using strings here as the generic parameter of the protocol. It's just happens to be my most recent usecase. Any type of data your function needs, you can represent it as an enum case thus making a custom namespace for your parameters!

Conclusion

As you can see, this is not one of those world changing discoveries, but rather a small bit of spark to make your APIs a bit nicer to use. If you want to see this in action, or just need a simple way of working with keychain, feel free to check out SecureStore and if you have any questions about this or any other topics, reach out to me on X

Follow me on X