Given a set of fields obtained through NamedTuple.From
, is it possible to retrieve the type of a named field through a type application?
I’m looking for something along lines of:
case class Person(name: String, age: Int)
type Fields = NamedTuple.From[Person]
type AgeField = Fields.Named["age"] // how do I do this?
thanks!
Best thing I could come up with is the following:
First, define a type for “index of” to obtain the index of a type within a tuple:
import scala.compiletime.ops.int.S
type IndexOfImpl[T <: Tuple, Elem, I <: Int] <: Int = T match
case EmptyTuple => -1
case Elem *: _ => I
case _ *: tail => IndexOfImpl[tail, Elem, S[I]]
type IndexOf[T <: Tuple, Elem] = IndexOfImpl[T, Elem, 0]
Then, define a type for “field by name” that uses IndexOf
to obtain the index of the name (from NamedTuple.Names
) and then uses NamedTuple.Elem
to obtain the type of the value at that index:
import scala.NamedTuple.AnyNamedTuple
type FieldByName[T <: AnyNamedTuple, Name <: String] =
NamedTuple.Elem[T, IndexOf[NamedTuple.Names[T], Name]]
With that, you can now do:
type AgeField = FieldByName[Fields, "age"]
val x: AgeField = 9
Found another approach that works as well - just obtain the names and field-types as separate types of Tuples and iterate through those:
import scala.NamedTuple.AnyNamedTuple
type FieldByNameImpl[Names <: Tuple, Fields <: Tuple, Name] = (Names, Fields) match
case (Name *: _, field *: _) => field
case (_ *: nTail, _ *: fTail) => FieldByNameImpl[nTail, fTail, Name]
type FieldByName[T <: AnyNamedTuple, Name <: String] =
FieldByNameImpl[NamedTuple.Names[T], NamedTuple.DropNames[T], Name]
1 Like
Nice, thank you for sharing this.
I also made progress independently but got stuck when trying to obtain a ClassTag
inside my inline def.
Details here:
Oddly, it works if you do not declare an intermediate type Fields
and rather define FieldTpe
in one line:
1 Like
Huh, interesting. Good find. Thank you again, this unblocks me!