Awesome
neotype
A friendly newtype library for Scala 3.
"io.github.kitlangton" %% "neotype" % "0.3.5"
Features
- Compile-time Checked Values
- Write validations as plain, old Scala expressions
- Helpful compilation errors (see below)
- No runtime allocations (Thanks to
inline
andopaque type
) - Integrates with other libraries (e.g.
zio-json
,circe
,tapir
, etc.)
5 Minute Video Tour
<a href="http://www.youtube.com/watch?v=6AxSX_WX7ek" title="NEOTYPE TOUR"> <img src="https://img.youtube.com/vi/6AxSX_WX7ek/maxresdefault.jpg" alt="NEOTYPE VIDEO TOUR" width="500" height="300"> </a>Example
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
———————————————————————————————————————————————————————————————————————————
Integrations
Neotype integrates with the following libraries:
- JSON
- DATABASE
- MISCELLANEOUS
- zio-test
DeriveGen
- zio-config
- zio-schema
- tapir
- chimney
- caliban
- zio-test
ZIO Json Example
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.