https://github.com/gaeljw/typetrees
This library is intended to solve the use case of getting the erased types of a (generic) parameter. Something which was possible in Scala 2 with TypeTag and is now a bit more complex with Scala 3.
https://github.com/gaeljw/typetrees
classtag generics scala scala3 typetag
Last synced: 4 months ago
JSON representation
This library is intended to solve the use case of getting the erased types of a (generic) parameter. Something which was possible in Scala 2 with TypeTag and is now a bit more complex with Scala 3.
- Host: GitHub
- URL: https://github.com/gaeljw/typetrees
- Owner: gaeljw
- License: apache-2.0
- Created: 2021-02-10T13:44:33.000Z (almost 5 years ago)
- Default Branch: main
- Last Pushed: 2025-08-10T15:34:55.000Z (5 months ago)
- Last Synced: 2025-08-10T17:26:26.113Z (5 months ago)
- Topics: classtag, generics, scala, scala3, typetag
- Language: Scala
- Homepage:
- Size: 101 KB
- Stars: 11
- Watchers: 1
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.adoc
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
:testdir: src/test/scala/io/github/gaeljw/typetrees
= TypeTrees
:toc:
[link=https://search.maven.org/artifact/io.github.gaeljw/typetrees_3]
image::https://img.shields.io/maven-central/v/io.github.gaeljw/typetrees_3.svg[]
image::https://github.com/gaeljw/typetrees/workflows/Scala%20CI/badge.svg[]
WARNING: (2025-05) This library served as a prototype and should not used in any real project.
It is unmaintained.
More robust projects (or even vanilla Scala depending on the context) exist to achieve the same.
This library is intended to solve the use case of getting the erased types of a (generic) parameter.
Something which was possible in Scala 2 with `+TypeTag+`
and is now a bit more complex with Scala 3.
== Get it
.sbt
[source]
----
libraryDependencies += "io.github.gaeljw" %% "typetrees" % typetreesVersion
----
.Maven
[source,xml]
----
io.github.gaeljw
typetrees_${scala.version}
${typetrees.version}
----
== Usage
Two implementations are available:
* using implicits (`given` s)
* using macro
|===
|Implementation |Pros 👍 |Cons 👎
|Implicits
|Easier
|Only supports up to 4 generic parameters (i.e. a type `T[A, B, C, D]`)
|Macro
|Can handle all cases
|Requires to be used in `inline` method
|===
=== Using implicits
[source,scala]
----
import io.github.gaeljw.typetrees.TypeTree
import io.github.gaeljw.typetrees.TypeTreeTag
import scala.reflect.ClassTag
val tag: TypeTreeTag = summon[TypeTree[T]].tag // <1>
val classTag: ClassTag[_] = tag.self // <2>
val actualClass: Class[_] = classTag.runtimeClass
val typeParameters: List[TypeTreeTag] = tag.args // <3>
----
<1> Get a `+TypeTreeTag+` for a generic type `+T+`
<2> Get a `+ClassTag+` for this type
<3> Get a `+TypeTreeTag+` for each type parameters if any
==== Examples
The main usage is as follows:
[source,scala]
----
def someGenericMethod[T](t: T)(using typeTree: TypeTree[T]): String = {
val tag: TypeTreeTag = typeTree.tag
s"I have been called with a parameter of type $tag"
}
someGenericMethod(Map[String, Int]())
// Gives: I have been called with a parameter of type TypeTreeTag(scala.collection.immutable.Map,List(TypeTreeTag(java.lang.String,List()), TypeTreeTag(Int,List())))
----
Or with context bounds:
[source,scala]
----
def someGenericMethod[T : TypeTree](t: T): String = {
val tag: TypeTreeTag = summon[TypeTree[T]].tag
s"I have been called with a parameter of type $tag"
}
----
You can find more examples in our link:{testdir}/TestBehaviorImplicits.scala[tests].
=== Using macro
[source,scala]
----
import io.github.gaeljw.typetrees.TypeTreeTag
import io.github.gaeljw.typetrees.TypeTreeTagMacros.typeTreeTag
import scala.reflect.ClassTag
val tag: TypeTreeTag = typeTreeTag[T] // <1>
val classTag: ClassTag[_] = tag.self // <2>
val actualClass: Class[_] = classTag.runtimeClass
val typeParameters: List[TypeTreeTag] = tag.args // <3>
----
<1> Get a `+TypeTreeTag+` for a generic type `+T+`
<2> Get a `+ClassTag+` for this type
<3> Get a `+TypeTreeTag+` for each type parameters if any
==== Examples
The main usage is as follows, within a generic `+inline+` method:
[source,scala]
----
inline def someGenericMethod[T](t: T): String = {
val tag: TypeTreeTag = typeTreeTag[T]
s"I have been called with a parameter of type $tag"
}
someGenericMethod(Map[String, Int]())
// Gives: I have been called with a parameter of type TypeTreeTag(scala.collection.immutable.Map,List(TypeTreeTag(java.lang.String,List()), TypeTreeTag(Int,List())))
----
Or:
[source,scala]
----
inline def someGenericMapMethod[T <: Map[_,_]](map: T): String = {
val mapTag: TypeTreeTag = typeTreeTag[T]
val keyTag: TypeTreeTag = mapTag.args(0)
val valueTag: TypeTreeTag = mapTag.args(1)
s"I have been called with a Map where key is of type $keyTag and value is of type $valueTag"
}
----
It can also be applied to non generic types: in such case it doesn't need to be part of a `+inline def+` but you probably can just use regular `ClassTag` then.
You can find more examples in our link:{testdir}/TestBehaviorMacro.scala[tests].