Skip to main content

TypeRef

TypeRef represents a reference to a Scala type in the IR. It captures both simple types (like String, Int) and generic types (like List[String], Map[String, Int]).

Use Cases

  • Specifying the types of fields in case classes
  • Defining return types of methods
  • Representing type arguments in generic types
  • Building complex nested type expressions

Construction

Create a simple type reference:

import zio.blocks.codegen.ir._

val stringType = TypeRef("String")
val intType = TypeRef("Int")
val booleanType = TypeRef("Boolean")

With type arguments for generics:

import zio.blocks.codegen.ir._

val listOfString = TypeRef("List", List(TypeRef("String")))
val mapStringInt = TypeRef("Map", List(TypeRef("String"), TypeRef("Int")))
val optionalLong = TypeRef("Option", List(TypeRef("Long")))

Using factory methods from the companion object:

import zio.blocks.codegen.ir._

val string = TypeRef.String
val int = TypeRef.Int
val optional = TypeRef.optional(TypeRef.String)
val list = TypeRef.list(TypeRef.Int)
val map = TypeRef.map(TypeRef.String, TypeRef.Int)

Key Operations

All core operations are shown below:

Accessing Components

Extract parts of a type reference:

import zio.blocks.codegen.ir._

val optional = TypeRef("Option", List(TypeRef.String))

optional.name // "Option"
optional.typeArgs // List[TypeRef] = List(TypeRef("String"))

Building Nested Types

Compose type references:

import zio.blocks.codegen.ir._
val nestedList = TypeRef("List", List(
TypeRef("Option", List(TypeRef("String")))
))
// Represents: List[Option[String]]

Primitive Types

TypeRef provides factory methods for built-in types:

import zio.blocks.codegen.ir._

TypeRef.Unit // Unit
TypeRef.Boolean // Boolean
TypeRef.Byte // Byte
TypeRef.Short // Short
TypeRef.Int // Int
TypeRef.Long // Long
TypeRef.Float // Float
TypeRef.Double // Double
TypeRef.String // String
TypeRef.BigInt // BigInt
TypeRef.BigDecimal // BigDecimal
TypeRef.Nothing // Nothing
TypeRef.Any // Any

Generic Type Factories

Convenience methods simplify common generic patterns:

import zio.blocks.codegen.ir._

TypeRef.optional(TypeRef.String) // Option[String]
TypeRef.list(TypeRef.Int) // List[Int]
TypeRef.set(TypeRef.String) // Set[String]
TypeRef.map(TypeRef.String, TypeRef.Int) // Map[String, Int]
TypeRef.tuple(TypeRef.String, TypeRef.Int) // Tuple2[String, Int]

Examples

Practical examples demonstrate common usage:

Example 1: Field Types

Use TypeRef to define field types in a case class:

import zio.blocks.codegen.ir._

val user = CaseClass(
name = "User",
fields = List(
Field("id", TypeRef.Long),
Field("name", TypeRef.String),
Field("email", TypeRef.optional(TypeRef.String)),
Field("tags", TypeRef.list(TypeRef.String))
)
)

Example 2: Generic Type Parameters

Use TypeRef with type variable names:

import zio.blocks.codegen.ir._

val container = CaseClass(
name = "Container",
fields = List(
Field("value", TypeRef("T"))
),
typeParams = List(TypeParam("T"))
)

Represents: Container[T] with a field value: T

Example 3: Complex Nested Generics

Build deeply nested type expressions:

import zio.blocks.codegen.ir._

val complexType = TypeRef("Map", List(
TypeRef.String,
TypeRef("List", List(
TypeRef("Option", List(TypeRef.Int))
))
))
// Represents: Map[String, List[Option[Int]]]

val field = Field("data", complexType)

Example 4: Qualified Type Names

Use fully qualified names for non-standard types:

import zio.blocks.codegen.ir._

val bigDecimal = TypeRef("java.math.BigDecimal")
val jsonObject = TypeRef("com.example.json.JsonObject")

val field1 = Field("price", bigDecimal)
val field2 = Field("metadata", jsonObject)

Example 5: Union and Intersection Types (Scala 3)

Represent Scala 3 union and intersection types:

import zio.blocks.codegen.ir._

// Represents: String | Int
val unionType = TypeRef("|", List(TypeRef.String, TypeRef.Int))

// Represents: Serializable & Comparable
val intersectionType = TypeRef("&", List(
TypeRef("Serializable"),
TypeRef("Comparable")
))