You will need a Mapped instance that will witness that T and type x have this relationship:
import shapeless._, ops.hlist.Mapped abstract class MyClass[T <: HList, OT <: HList](implicit mapped: Mapped.Aux[T, Option, OT] ) { val x: OT }
Unfortunately, this is inconvenient to instantiate:
new MyClass[Int :: String :: HNil, Option[Int] :: Option[String] :: HNil] { val x = Some(0) :: Some("") :: HNil }
There are ways around this, but they require additional changes. For example, you can enable the output of two parameters of the type:
import shapeless._, ops.hlist.Comapped class MyClass[T <: HList, OT <: HList](val x: OT)(implicit mapped: Comapped.Aux[OT, Option, T] )
And then:
new MyClass(Option(0) :: Option("") :: HNil)
Or you can use something closer to your source class using a special constructor in the companion object:
import shapeless._, ops.hlist.Mapped abstract class MyClass[T <: HList] { type OT <: HList def mapped: Mapped.Aux[T, Option, OT] val x: OT } object MyClass { class PartiallyApplied[T <: HList] { def apply[OT0 <: HList](x0: OT0)(implicit mapped0: Mapped.Aux[T, Option, OT0] ): MyClass[T] = new MyClass[T] { type OT = OT0 val mapped: Mapped.Aux[T, Option, OT] = mapped0 val x: OT = x0 } } def apply[T <: HList]: PartiallyApplied[T] = new PartiallyApplied[T] }
And then:
MyClass[Int :: String :: HNil](Option(0) :: Option("") :: HNil)
Which of these approaches is more appropriate will depend on how you use the class.