A friendly newtype library for Scala 3.
"io.github.kitlangton" %% "neotype" % "0.3.0"
inline
and opaque type
)zio-json
, circe
, tapir
, etc.)Here is how to define a compile-time validated Newtype.
import neotype.*
// 1. Define a newtype.
object NonEmptyString extends Newtype[String]:
// 2. Optionally, define a validate method.
override inline def validate(input: String): Boolean =
input.nonEmpty
// 3. Construct values.
NonEmptyString("Hello") // OK
NonEmptyString("") // Compile Error
Attempting to call NonEmptyString("")
would result in the following compilation error:
Error: /src/main/scala/examples/Main.scala:9:16
NonEmptyString("")
^^^^^^^^^^^^^^^^^^
—— Newtype Error ——————————————————————————————————————————————————————————
NonEmptyString was called with an INVALID String.
input: ""
check: input.nonEmpty
———————————————————————————————————————————————————————————————————————————
Neotype integrates with the following libraries:
DeriveGen
import neotype.*
type NonEmptyString = NonEmptyString.Type
object NonEmptyString extends Newtype[String]:
override inline def validate(value: String): Result =
if value.nonEmpty then true else "String must not be empty"
import neotype.interop.ziojson.given
import zio.json.*
case class Person(name: NonEmptyString, age: Int) derives JsonCodec
val parsed = """{"name": "Kit", "age": 30}""".fromJson[Person]
// Right(Person(NonEmptyString("Kit"), 30))
val failed = """{"name": "", "age": 30}""".fromJson[Person]
// Left(".name(String must not be empty)")
By importing neotype.ziojson.given
, we automatically generate a JsonCodec
for NonEmptyString
. Custom
failure messages are also supported (by overriding def failureMessage
in the Newtype definition).
Note that import neotype.interop.ziojson.given
needs to be in the same file as Person
, not NonEmptyString
.
The generated JsonCodec
is not made available to the entire project, but only to the file where it is imported.