@zio.dev/zio-blocks 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,900 @@
1
+ ---
2
+ id: typeid
3
+ title: "TypeId"
4
+ ---
5
+
6
+ # TypeId
7
+
8
+ `TypeId[A]` represents the identity of a type or type constructor at runtime. It provides rich type identity information including the type's name, owner (package/class/object), type parameters, classification (nominal, alias, or opaque), parent types, and annotations.
9
+
10
+ ## Overview
11
+
12
+ TypeId is fundamental to ZIO Blocks' schema system, enabling:
13
+
14
+ - **Type identification** - Uniquely identify types across serialization boundaries
15
+ - **Subtype checking** - Determine inheritance relationships at runtime
16
+ - **Type normalization** - Resolve type aliases to their underlying types
17
+ - **Schema derivation** - Automatically derive schemas for user-defined types
18
+
19
+ ```scala
20
+ import zio.blocks.typeid._
21
+
22
+ // Derive TypeId for your types
23
+ case class Person(name: String, age: Int)
24
+ val personId: TypeId[Person] = TypeId.of[Person]
25
+
26
+ // Access type information
27
+ personId.name // "Person"
28
+ personId.fullName // "com.example.Person"
29
+ personId.isCaseClass // true
30
+
31
+ // Use predefined TypeIds
32
+ TypeId.int.fullName // "scala.Int"
33
+ TypeId.string.fullName // "java.lang.String"
34
+ TypeId.list.arity // 1 (type constructor)
35
+ ```
36
+
37
+ ## Installation
38
+
39
+ TypeId is included in the `zio-blocks-typeid` module. Add it to your build:
40
+
41
+ ```scala
42
+ libraryDependencies += "dev.zio" %% "zio-blocks-typeid" % "<version>"
43
+ ```
44
+
45
+ Cross-platform support: TypeId works on JVM and Scala.js.
46
+
47
+ ## Creating TypeIds
48
+
49
+ ### Automatic Derivation
50
+
51
+ The simplest way to get a TypeId is via macro derivation:
52
+
53
+ ```scala
54
+ import zio.blocks.typeid._
55
+
56
+ case class User(id: Long, email: String)
57
+
58
+ // Scala 3
59
+ val userId: TypeId[User] = TypeId.of[User]
60
+
61
+ // Scala 2
62
+ val userId: TypeId[User] = TypeId.of[User]
63
+
64
+ // Or use implicit derivation
65
+ val userId: TypeId[User] = implicitly[TypeId[User]]
66
+ ```
67
+
68
+ The macro extracts complete type information including:
69
+ - Type name and owner
70
+ - Type parameters and variance
71
+ - Parent types (for sealed traits and enums)
72
+ - Whether it's a case class, sealed trait, enum, etc.
73
+
74
+ ### Manual Construction
75
+
76
+ For manual type registration or testing, use smart constructors:
77
+
78
+ ```scala
79
+ // Nominal types (classes, traits, objects)
80
+ val myTypeId = TypeId.nominal[MyType](
81
+ name = "MyType",
82
+ owner = Owner.fromPackagePath("com.example"),
83
+ defKind = TypeDefKind.Class(isCase = true)
84
+ )
85
+
86
+ // Type aliases
87
+ val aliasId = TypeId.alias[Age](
88
+ name = "Age",
89
+ owner = Owner.fromPackagePath("com.example"),
90
+ aliased = TypeRepr.Ref(TypeId.int)
91
+ )
92
+
93
+ // Opaque types (Scala 3)
94
+ val emailId = TypeId.opaque[Email](
95
+ name = "Email",
96
+ owner = Owner.fromPackagePath("com.example"),
97
+ representation = TypeRepr.Ref(TypeId.string)
98
+ )
99
+ ```
100
+
101
+ ### Applied Types
102
+
103
+ Create applied types (type constructors with arguments):
104
+
105
+ ```scala
106
+ // List[Int]
107
+ val listIntId = TypeId.applied[List[Int]](
108
+ TypeId.list,
109
+ TypeRepr.Ref(TypeId.int)
110
+ )
111
+
112
+ // Map[String, Int]
113
+ val mapId = TypeId.applied[Map[String, Int]](
114
+ TypeId.map,
115
+ TypeRepr.Ref(TypeId.string),
116
+ TypeRepr.Ref(TypeId.int)
117
+ )
118
+ ```
119
+
120
+ ## TypeId Properties
121
+
122
+ ### Basic Properties
123
+
124
+ ```scala
125
+ val id = TypeId.of[Person]
126
+
127
+ id.name // "Person" - simple name
128
+ id.fullName // "com.example.Person" - fully qualified
129
+ id.owner // Owner representing the package/enclosing type
130
+ id.arity // 0 for proper types, n for type constructors
131
+ id.typeParams // List of TypeParam for type constructors
132
+ id.typeArgs // List of TypeRepr for applied types
133
+ ```
134
+
135
+ ### Type Classification
136
+
137
+ ```scala
138
+ id.isClass // true for classes
139
+ id.isTrait // true for traits
140
+ id.isObject // true for singleton objects
141
+ id.isEnum // true for Scala 3 enums
142
+ id.isCaseClass // true for case classes
143
+ id.isValueClass // true for value classes (extends AnyVal)
144
+ id.isSealed // true for sealed traits
145
+ id.isAlias // true for type aliases
146
+ id.isOpaque // true for opaque types
147
+ id.isAbstract // true for abstract type members
148
+
149
+ id.isProperType // arity == 0
150
+ id.isTypeConstructor // arity > 0
151
+ id.isApplied // has type arguments
152
+ ```
153
+
154
+ ### Common Type Checks
155
+
156
+ ```scala
157
+ id.isTuple // scala.TupleN
158
+ id.isProduct // scala.ProductN
159
+ id.isSum // Either or Option
160
+ id.isEither // scala.util.Either
161
+ id.isOption // scala.Option
162
+ ```
163
+
164
+ ### Subtype Relationships
165
+
166
+ ```scala
167
+ sealed trait Animal
168
+ case class Dog(name: String) extends Animal
169
+
170
+ val dogId = TypeId.of[Dog]
171
+ val animalId = TypeId.of[Animal]
172
+
173
+ dogId.isSubtypeOf(animalId) // true
174
+ animalId.isSupertypeOf(dogId) // true
175
+ dogId.isEquivalentTo(dogId) // true
176
+ ```
177
+
178
+ Subtype checking handles:
179
+ - Direct inheritance
180
+ - Enum cases and their parent enums
181
+ - Sealed trait subtypes
182
+ - Transitive inheritance
183
+ - Variance-aware subtyping for applied types
184
+
185
+ ### Pattern Matching
186
+
187
+ TypeId provides extractors for pattern matching:
188
+
189
+ ```scala
190
+ typeId match {
191
+ case TypeId.Nominal(name, owner, params, defKind, parents) =>
192
+ // Regular types
193
+
194
+ case TypeId.Alias(name, owner, params, aliased) =>
195
+ // Type aliases - aliased is the underlying TypeRepr
196
+
197
+ case TypeId.Opaque(name, owner, params, repr, bounds) =>
198
+ // Opaque types - repr is the representation type
199
+
200
+ case TypeId.Sealed(name) =>
201
+ // Sealed traits
202
+
203
+ case TypeId.Enum(name, owner) =>
204
+ // Scala 3 enums
205
+ }
206
+ ```
207
+
208
+ ## TypeRepr
209
+
210
+ `TypeRepr` represents type expressions in the Scala type system. While `TypeId` identifies a type definition, `TypeRepr` represents how types are used in expressions.
211
+
212
+ ### Basic Type References
213
+
214
+ ```scala
215
+ // Reference to a named type
216
+ TypeRepr.Ref(TypeId.int) // Int
217
+ TypeRepr.Ref(TypeId.string) // String
218
+
219
+ // Reference to a type parameter
220
+ TypeRepr.ParamRef(TypeParam.A) // A
221
+ TypeRepr.ParamRef(param, depth = 1) // nested binder reference
222
+ ```
223
+
224
+ ### Applied Types
225
+
226
+ ```scala
227
+ // List[Int]
228
+ TypeRepr.Applied(
229
+ TypeRepr.Ref(TypeId.list),
230
+ List(TypeRepr.Ref(TypeId.int))
231
+ )
232
+
233
+ // Map[String, Int]
234
+ TypeRepr.Applied(
235
+ TypeRepr.Ref(TypeId.map),
236
+ List(TypeRepr.Ref(TypeId.string), TypeRepr.Ref(TypeId.int))
237
+ )
238
+ ```
239
+
240
+ ### Compound Types
241
+
242
+ ```scala
243
+ // Intersection: A & B (Scala 3) or A with B (Scala 2)
244
+ TypeRepr.Intersection(List(typeA, typeB))
245
+
246
+ // Union: A | B (Scala 3 only)
247
+ TypeRepr.Union(List(typeA, typeB))
248
+
249
+ // Convenience constructors handle edge cases
250
+ TypeRepr.intersection(List(typeA)) // returns typeA (not Intersection)
251
+ TypeRepr.intersection(Nil) // returns AnyType
252
+ TypeRepr.union(List(typeA)) // returns typeA
253
+ TypeRepr.union(Nil) // returns NothingType
254
+ ```
255
+
256
+ ### Function Types
257
+
258
+ ```scala
259
+ // A => B
260
+ TypeRepr.Function(List(typeA), typeB)
261
+
262
+ // (A, B) => C
263
+ TypeRepr.Function(List(typeA, typeB), typeC)
264
+
265
+ // (A, B) ?=> C (context function, Scala 3)
266
+ TypeRepr.ContextFunction(List(typeA, typeB), typeC)
267
+ ```
268
+
269
+ ### Tuple Types
270
+
271
+ ```scala
272
+ // (A, B, C)
273
+ TypeRepr.Tuple(List(
274
+ TupleElement(None, typeA),
275
+ TupleElement(None, typeB),
276
+ TupleElement(None, typeC)
277
+ ))
278
+
279
+ // Named tuples (Scala 3.5+): (name: String, age: Int)
280
+ TypeRepr.Tuple(List(
281
+ TupleElement(Some("name"), TypeRepr.Ref(TypeId.string)),
282
+ TupleElement(Some("age"), TypeRepr.Ref(TypeId.int))
283
+ ))
284
+
285
+ // Convenience for unnamed tuples
286
+ TypeRepr.tuple(List(typeA, typeB, typeC))
287
+ ```
288
+
289
+ ### Structural Types
290
+
291
+ ```scala
292
+ // { def foo: Int }
293
+ TypeRepr.Structural(
294
+ parents = Nil,
295
+ members = List(
296
+ Member.Def("foo", Nil, Nil, TypeRepr.Ref(TypeId.int))
297
+ )
298
+ )
299
+
300
+ // AnyRef { type T; val x: T }
301
+ TypeRepr.Structural(
302
+ parents = List(TypeRepr.Ref(anyRefId)),
303
+ members = List(
304
+ Member.TypeMember("T"),
305
+ Member.Val("x", TypeRepr.ParamRef(paramT))
306
+ )
307
+ )
308
+ ```
309
+
310
+ ### Path-Dependent and Singleton Types
311
+
312
+ ```scala
313
+ // x.type (singleton type)
314
+ TypeRepr.Singleton(TermPath.fromOwner(owner, "x"))
315
+
316
+ // this.type
317
+ TypeRepr.ThisType(owner)
318
+
319
+ // Outer#Inner (type projection)
320
+ TypeRepr.TypeProjection(outerType, "Inner")
321
+
322
+ // qualifier.Member (type selection)
323
+ TypeRepr.TypeSelect(qualifierType, "Member")
324
+ ```
325
+
326
+ ### Special Types
327
+
328
+ ```scala
329
+ TypeRepr.AnyType // Any
330
+ TypeRepr.NothingType // Nothing
331
+ TypeRepr.NullType // Null
332
+ TypeRepr.UnitType // Unit
333
+ TypeRepr.AnyKindType // AnyKind (for kind-polymorphic contexts)
334
+ ```
335
+
336
+ ### Constant/Literal Types
337
+
338
+ ```scala
339
+ TypeRepr.Constant.IntConst(42) // 42 (literal type)
340
+ TypeRepr.Constant.StringConst("foo") // "foo"
341
+ TypeRepr.Constant.BooleanConst(true) // true
342
+ TypeRepr.Constant.ClassOfConst(tpe) // classOf[T]
343
+ ```
344
+
345
+ ### Type Lambdas (Scala 3)
346
+
347
+ ```scala
348
+ // [X] =>> F[X]
349
+ TypeRepr.TypeLambda(
350
+ params = List(TypeParam("X", 0)),
351
+ body = TypeRepr.Applied(
352
+ TypeRepr.ParamRef(paramF),
353
+ List(TypeRepr.ParamRef(paramX))
354
+ )
355
+ )
356
+ ```
357
+
358
+ ### Wildcards and Bounds
359
+
360
+ ```scala
361
+ // ?
362
+ TypeRepr.Wildcard()
363
+
364
+ // ? <: Upper
365
+ TypeRepr.Wildcard(TypeBounds.upper(upperType))
366
+
367
+ // ? >: Lower
368
+ TypeRepr.Wildcard(TypeBounds.lower(lowerType))
369
+
370
+ // ? >: Lower <: Upper
371
+ TypeRepr.Wildcard(TypeBounds(lowerType, upperType))
372
+ ```
373
+
374
+ ### Parameter Modifiers
375
+
376
+ ```scala
377
+ // => A (by-name)
378
+ TypeRepr.ByName(typeA)
379
+
380
+ // A* (varargs/repeated)
381
+ TypeRepr.Repeated(typeA)
382
+
383
+ // A @annotation
384
+ TypeRepr.Annotated(typeA, List(annotation))
385
+ ```
386
+
387
+ ## Namespaces and Type Names
388
+
389
+ ### Owner
390
+
391
+ `Owner` represents where a type is defined in the package hierarchy:
392
+
393
+ ```scala
394
+ // From package path
395
+ val owner = Owner.fromPackagePath("com.example.app")
396
+ // Owner(List(Package("com"), Package("example"), Package("app")))
397
+
398
+ // Build incrementally
399
+ val owner = Owner.Root / "com" / "example"
400
+
401
+ // Add term (object) segment
402
+ val owner = (Owner.Root / "com").term("MyObject")
403
+
404
+ // Add type segment
405
+ val owner = (Owner.Root / "com").tpe("MyClass")
406
+ ```
407
+
408
+ Owner properties:
409
+
410
+ ```scala
411
+ owner.asString // "com.example" - dot-separated path
412
+ owner.isRoot // true if empty
413
+ owner.parent // Parent owner (or Root)
414
+ owner.lastName // Last segment name
415
+ ```
416
+
417
+ ### Predefined Owners
418
+
419
+ TypeId provides common namespaces:
420
+
421
+ ```scala
422
+ Owner.scala // scala
423
+ Owner.scalaUtil // scala.util
424
+ Owner.scalaCollectionImmutable // scala.collection.immutable
425
+ Owner.javaLang // java.lang
426
+ Owner.javaTime // java.time
427
+ Owner.javaUtil // java.util
428
+ ```
429
+
430
+ ### TermPath
431
+
432
+ `TermPath` represents paths to term values (for singleton types):
433
+
434
+ ```scala
435
+ // com.example.MyObject.value.type
436
+ val path = TermPath.fromOwner(
437
+ Owner.fromPackagePath("com.example").term("MyObject"),
438
+ "value"
439
+ )
440
+
441
+ path.asString // "com.example.MyObject.value"
442
+ path.isEmpty // false
443
+ path / "nested" // Append segment
444
+ ```
445
+
446
+ ## Type Parameters
447
+
448
+ ### TypeParam
449
+
450
+ Represents a type parameter specification:
451
+
452
+ ```scala
453
+ // Basic type parameter
454
+ TypeParam("A", index = 0)
455
+
456
+ // Covariant (+A)
457
+ TypeParam("A", 0, Variance.Covariant)
458
+ TypeParam.covariant("A", 0)
459
+
460
+ // Contravariant (-A)
461
+ TypeParam("A", 0, Variance.Contravariant)
462
+ TypeParam.contravariant("A", 0)
463
+
464
+ // With bounds (A <: Upper)
465
+ TypeParam.bounded("A", 0, upper = TypeRepr.Ref(upperType))
466
+
467
+ // Higher-kinded (F[_])
468
+ TypeParam.higherKinded("F", 0, arity = 1)
469
+ TypeParam("F", 0, kind = Kind.Star1)
470
+
471
+ // Full specification
472
+ TypeParam(
473
+ name = "A",
474
+ index = 0,
475
+ variance = Variance.Covariant,
476
+ bounds = TypeBounds.upper(someType),
477
+ kind = Kind.Type
478
+ )
479
+ ```
480
+
481
+ TypeParam properties:
482
+
483
+ ```scala
484
+ param.name // "A"
485
+ param.index // Position in parameter list
486
+ param.variance // Covariant, Contravariant, or Invariant
487
+ param.bounds // TypeBounds
488
+ param.kind // Kind (*, * -> *, etc.)
489
+
490
+ param.isCovariant // variance == Covariant
491
+ param.isContravariant // variance == Contravariant
492
+ param.isInvariant // variance == Invariant
493
+ param.hasUpperBound // bounds.upper.isDefined
494
+ param.hasLowerBound // bounds.lower.isDefined
495
+ param.isProperType // kind == Kind.Type
496
+ param.isTypeConstructor // kind != Kind.Type
497
+ ```
498
+
499
+ ### TypeBounds
500
+
501
+ Represents type parameter bounds:
502
+
503
+ ```scala
504
+ // No bounds (>: Nothing <: Any)
505
+ TypeBounds.Unbounded
506
+
507
+ // Upper bound only (<: Upper)
508
+ TypeBounds.upper(upperType)
509
+
510
+ // Lower bound only (>: Lower)
511
+ TypeBounds.lower(lowerType)
512
+
513
+ // Both bounds (>: Lower <: Upper)
514
+ TypeBounds(lowerType, upperType)
515
+
516
+ // Type alias bounds (lower == upper)
517
+ TypeBounds.alias(aliasType)
518
+ ```
519
+
520
+ TypeBounds properties:
521
+
522
+ ```scala
523
+ bounds.lower // Option[TypeRepr]
524
+ bounds.upper // Option[TypeRepr]
525
+ bounds.isUnbounded // No bounds specified
526
+ bounds.hasOnlyUpper // Only upper bound
527
+ bounds.hasOnlyLower // Only lower bound
528
+ bounds.hasBothBounds // Both bounds specified
529
+ bounds.isAlias // lower == upper
530
+ bounds.aliasType // Option[TypeRepr] if alias
531
+ ```
532
+
533
+ ### Variance
534
+
535
+ ```scala
536
+ Variance.Covariant // +A
537
+ Variance.Contravariant // -A
538
+ Variance.Invariant // A
539
+
540
+ variance.symbol // "+", "-", or ""
541
+ variance.isCovariant
542
+ variance.isContravariant
543
+ variance.isInvariant
544
+ variance.flip // Covariant <-> Contravariant
545
+ variance * other // Combine variances
546
+ ```
547
+
548
+ ### Kind
549
+
550
+ Represents the "kind" of a type (type of types):
551
+
552
+ ```scala
553
+ Kind.Type // * (proper type like Int, String)
554
+ Kind.Star // Alias for Type
555
+ Kind.Star1 // * -> * (List, Option)
556
+ Kind.Star2 // * -> * -> * (Map, Either)
557
+ Kind.HigherStar1 // (* -> *) -> * (Functor, Monad)
558
+
559
+ Kind.constructor(0) // *
560
+ Kind.constructor(1) // * -> *
561
+ Kind.constructor(2) // * -> * -> *
562
+
563
+ // Custom kinds
564
+ Kind.Arrow(List(Kind.Type), Kind.Type) // * -> *
565
+ Kind.Arrow(List(Kind.Star1), Kind.Type) // (* -> *) -> *
566
+ ```
567
+
568
+ Kind properties:
569
+
570
+ ```scala
571
+ kind.isProperType // kind == Kind.Type
572
+ kind.arity // Number of type parameters
573
+ ```
574
+
575
+ ## Members (Structural Types)
576
+
577
+ ### Val/Var Members
578
+
579
+ ```scala
580
+ // val x: Int
581
+ Member.Val("x", TypeRepr.Ref(TypeId.int))
582
+
583
+ // var y: String
584
+ Member.Val("y", TypeRepr.Ref(TypeId.string), isVar = true)
585
+ ```
586
+
587
+ ### Method Members
588
+
589
+ ```scala
590
+ // def foo: Int
591
+ Member.Def("foo", Nil, Nil, TypeRepr.Ref(TypeId.int))
592
+
593
+ // def bar(x: Int): String
594
+ Member.Def(
595
+ name = "bar",
596
+ typeParams = Nil,
597
+ paramLists = List(List(Param("x", TypeRepr.Ref(TypeId.int)))),
598
+ result = TypeRepr.Ref(TypeId.string)
599
+ )
600
+
601
+ // def baz[A](x: A)(implicit y: Ordering[A]): List[A]
602
+ Member.Def(
603
+ name = "baz",
604
+ typeParams = List(TypeParam.A),
605
+ paramLists = List(
606
+ List(Param("x", TypeRepr.ParamRef(TypeParam.A))),
607
+ List(Param("y", orderingA, isImplicit = true))
608
+ ),
609
+ result = listA
610
+ )
611
+ ```
612
+
613
+ ### Type Members
614
+
615
+ ```scala
616
+ // type T
617
+ Member.TypeMember("T")
618
+
619
+ // type T <: Upper
620
+ Member.TypeMember("T", upperBound = Some(upperType))
621
+
622
+ // type T = Alias (isAlias when lower == upper)
623
+ Member.TypeMember("T",
624
+ lowerBound = Some(aliasType),
625
+ upperBound = Some(aliasType)
626
+ )
627
+ ```
628
+
629
+ ## TypeDefKind
630
+
631
+ Classifies what kind of type definition a TypeId represents:
632
+
633
+ ### Class
634
+
635
+ ```scala
636
+ TypeDefKind.Class(
637
+ isFinal = false,
638
+ isAbstract = false,
639
+ isCase = true, // case class
640
+ isValue = false, // extends AnyVal
641
+ bases = List(...) // parent types
642
+ )
643
+ ```
644
+
645
+ ### Trait
646
+
647
+ ```scala
648
+ TypeDefKind.Trait(
649
+ isSealed = true,
650
+ bases = List(...)
651
+ )
652
+ ```
653
+
654
+ ### Object
655
+
656
+ ```scala
657
+ TypeDefKind.Object(
658
+ bases = List(...)
659
+ )
660
+ ```
661
+
662
+ ### Enum (Scala 3)
663
+
664
+ ```scala
665
+ TypeDefKind.Enum(
666
+ bases = List(...)
667
+ )
668
+
669
+ TypeDefKind.EnumCase(
670
+ parentEnum = parentEnumRef,
671
+ ordinal = 0,
672
+ isObjectCase = true
673
+ )
674
+ ```
675
+
676
+ ### Type Aliases and Opaque Types
677
+
678
+ ```scala
679
+ TypeDefKind.TypeAlias // type Foo = Bar
680
+
681
+ TypeDefKind.OpaqueType(
682
+ publicBounds = TypeBounds.Unbounded // Bounds visible outside
683
+ )
684
+
685
+ TypeDefKind.AbstractType // Abstract type member
686
+ ```
687
+
688
+ ## Annotations
689
+
690
+ Represent Scala/Java annotations attached to types:
691
+
692
+ ```scala
693
+ Annotation(
694
+ typeId = TypeId.of[deprecated],
695
+ args = List(
696
+ AnnotationArg.Named("message",
697
+ AnnotationArg.Const("use newMethod")),
698
+ AnnotationArg.Named("since",
699
+ AnnotationArg.Const("1.0"))
700
+ )
701
+ )
702
+ ```
703
+
704
+ Annotation argument types:
705
+
706
+ ```scala
707
+ AnnotationArg.Const(value) // Constant value
708
+ AnnotationArg.ArrayArg(values) // Array of args
709
+ AnnotationArg.Named(name, value) // Named parameter
710
+ AnnotationArg.Nested(annotation) // Nested annotation
711
+ AnnotationArg.ClassOf(typeRepr) // classOf[T]
712
+ AnnotationArg.EnumValue(enumType, valueName) // Enum constant
713
+ ```
714
+
715
+ ## Predefined TypeIds
716
+
717
+ TypeId provides instances for common types:
718
+
719
+ ### Primitives
720
+
721
+ ```scala
722
+ TypeId.unit // scala.Unit
723
+ TypeId.boolean // scala.Boolean
724
+ TypeId.byte // scala.Byte
725
+ TypeId.short // scala.Short
726
+ TypeId.int // scala.Int
727
+ TypeId.long // scala.Long
728
+ TypeId.float // scala.Float
729
+ TypeId.double // scala.Double
730
+ TypeId.char // scala.Char
731
+ TypeId.string // java.lang.String
732
+ TypeId.bigInt // scala.BigInt
733
+ TypeId.bigDecimal // scala.BigDecimal
734
+ ```
735
+
736
+ ### Collections
737
+
738
+ ```scala
739
+ TypeId.option // scala.Option
740
+ TypeId.some // scala.Some
741
+ TypeId.none // scala.None
742
+ TypeId.list // scala.collection.immutable.List
743
+ TypeId.vector // scala.collection.immutable.Vector
744
+ TypeId.set // scala.collection.immutable.Set
745
+ TypeId.seq // scala.collection.immutable.Seq
746
+ TypeId.indexedSeq // scala.collection.immutable.IndexedSeq
747
+ TypeId.map // scala.collection.immutable.Map
748
+ TypeId.either // scala.util.Either
749
+ TypeId.array // scala.Array
750
+ TypeId.arraySeq // scala.collection.immutable.ArraySeq
751
+ TypeId.chunk // zio.blocks.chunk.Chunk
752
+ ```
753
+
754
+ ### java.time Types
755
+
756
+ ```scala
757
+ TypeId.dayOfWeek // java.time.DayOfWeek
758
+ TypeId.duration // java.time.Duration
759
+ TypeId.instant // java.time.Instant
760
+ TypeId.localDate // java.time.LocalDate
761
+ TypeId.localDateTime // java.time.LocalDateTime
762
+ TypeId.localTime // java.time.LocalTime
763
+ TypeId.month // java.time.Month
764
+ TypeId.monthDay // java.time.MonthDay
765
+ TypeId.offsetDateTime // java.time.OffsetDateTime
766
+ TypeId.offsetTime // java.time.OffsetTime
767
+ TypeId.period // java.time.Period
768
+ TypeId.year // java.time.Year
769
+ TypeId.yearMonth // java.time.YearMonth
770
+ TypeId.zoneId // java.time.ZoneId
771
+ TypeId.zoneOffset // java.time.ZoneOffset
772
+ TypeId.zonedDateTime // java.time.ZonedDateTime
773
+ ```
774
+
775
+ ### java.util Types
776
+
777
+ ```scala
778
+ TypeId.currency // java.util.Currency
779
+ TypeId.uuid // java.util.UUID
780
+ ```
781
+
782
+ ## Integration with Schema
783
+
784
+ TypeId is central to ZIO Blocks' schema system. Every `Reflect` node has an associated TypeId:
785
+
786
+ ```scala
787
+ import zio.blocks.schema._
788
+
789
+ case class Person(name: String, age: Int)
790
+ object Person {
791
+ implicit val schema: Schema[Person] = Schema.derived
792
+ }
793
+
794
+ // Access TypeId from schema
795
+ val reflect = Schema[Person].reflect
796
+ val typeId = reflect.typeId
797
+
798
+ typeId.name // "Person"
799
+ typeId.isCaseClass // true
800
+ ```
801
+
802
+ ### Schema Transformations
803
+
804
+ TypeId is captured when transforming schemas:
805
+
806
+ ```scala
807
+ case class Email(value: String)
808
+
809
+ object Email {
810
+ implicit val schema: Schema[Email] = Schema[String]
811
+ .transform(Email(_), _.value)
812
+ .withTypeName[Email] // Sets TypeId to Email
813
+ }
814
+ ```
815
+
816
+ ### Schema Derivation
817
+
818
+ The `Deriver` trait receives TypeId for each node:
819
+
820
+ ```scala
821
+ trait Deriver[TC[_]] {
822
+ def deriveRecord[A](
823
+ typeId: TypeId[A],
824
+ fields: => Chunk[Deriver.Field[TC, A, _]],
825
+ ...
826
+ ): TC[A]
827
+
828
+ def deriveVariant[A](
829
+ typeId: TypeId[A],
830
+ cases: => Chunk[Deriver.Case[TC, A, _]],
831
+ ...
832
+ ): TC[A]
833
+
834
+ // ... other methods
835
+ }
836
+ ```
837
+
838
+ ## Type Normalization
839
+
840
+ Type aliases are normalized to their underlying types for comparison:
841
+
842
+ ```scala
843
+ type Age = Int
844
+
845
+ val ageId = TypeId.alias[Age]("Age", owner, Nil, TypeRepr.Ref(TypeId.int))
846
+ val normalized = TypeId.normalize(ageId)
847
+
848
+ normalized.fullName // "scala.Int" (not "Age")
849
+ ```
850
+
851
+ Normalization handles nested aliases and type arguments:
852
+
853
+ ```scala
854
+ type IntList = List[Int]
855
+ type MyIntList = IntList
856
+
857
+ // Normalizing MyIntList resolves through IntList to List[Int]
858
+ ```
859
+
860
+ ## Equality and Hashing
861
+
862
+ TypeId uses structural equality that accounts for type aliases:
863
+
864
+ ```scala
865
+ val alias1 = TypeId.alias[A]("A", owner, Nil, TypeRepr.Ref(TypeId.int))
866
+ val alias2 = TypeId.alias[A]("A", owner, Nil, TypeRepr.Ref(TypeId.int))
867
+
868
+ alias1 == alias2 // true (structural equality)
869
+
870
+ // Works correctly in hash maps
871
+ val map = Map(alias1 -> "value")
872
+ map(alias2) // "value"
873
+ ```
874
+
875
+ ## Erased TypeId
876
+
877
+ For type-indexed collections where the type parameter doesn't matter:
878
+
879
+ ```scala
880
+ // TypeId.Erased is TypeId[TypeId.Unknown]
881
+ val erased: TypeId.Erased = typeId.erased
882
+
883
+ // Use in maps keyed by type
884
+ val typeRegistry: Map[TypeId.Erased, Schema[_]] = Map(
885
+ TypeId.int.erased -> Schema[Int],
886
+ TypeId.string.erased -> Schema[String]
887
+ )
888
+ ```
889
+
890
+ ## Runtime Reflection
891
+
892
+ On JVM, TypeId can retrieve the corresponding `Class`:
893
+
894
+ ```scala
895
+ val typeId = TypeId.of[Person]
896
+ val clazz: Option[Class[_]] = typeId.clazz
897
+
898
+ // Construct instances (JVM only)
899
+ val result: Either[String, Any] = typeId.construct(Chunk("Alice", 30))
900
+ ```