A friendly newtype library for Scala 3.
"io.github.kitlangton" %% "neotype" % "0.3.29"- Compile-time Checked Values
- Write validations as plain, old Scala expressions
- Helpful compilation errors (see below)
- No runtime allocations (Thanks to
inlineandopaque type) - Integrates with other libraries (e.g.
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 ErrorAttempting 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:
- JSON
- DATABASE
- MISCELLANEOUS
- zio-test
DeriveGen - zio-config
- zio-schema
- tapir
- chimney
- caliban
- ciris
- cats
Show,Eq,Order
- zio-test
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.