Now that we covered all ways to « Create Props, let’s look closer at one more API that is unsafe.
When creating a Props, the preferred way is to use the (Class[_], Any*) overload, since this one does not create a closure.
If you create a props from within an Actor using the (=> Actor) overload, you accidentally close over the ActorContext, that’s shared state you don’t want.
The problem with the constructor using Class, you don’t get any help from the compiler. If you change one parameter, there is nothing telling you to change the Props constructor but the eventual runtime error (from your tests, hopefully).

Using shapeless, we can try to fix this issue.

Using the creator module

The types creator lives in a separate module that you have to include first.

libraryDependencies += "de.knutwalker" %% "typed-actors-creator" % "1.6.0"

Next, you have to use the TypedActor trait and you have to make your actor a case class.
This is necessary, so that shapeless’ generic machinery can pick up the required constructor parameters.

case class MyActor(param: String) extends TypedActor.Of[MyMessage] {
  def typedReceive = {
    case Foo(foo) => println(s"$param - received a Foo: $foo")
    case Bar(bar) => println(s"$param - received a Bar: $bar")
  }
}

Next, use the Typed constructor. It takes one type parameter, which is supposed to be your TypedActor.
Now you can use two methods, props and create. Both accept the same arguments as the constructor of your TypedActor and will either return a typed Props or typed ActorRef, respectively (thanks to some shapeless magic).

scala> Typed[MyActor].props("Bernd")
res0: de.knutwalker.akka.typed.Props[MyMessage] = Props(Deploy(,Config(SimpleConfigObject({})),NoRouter,NoScopeGiven,,),class akka.actor.TypedCreatorFunctionConsumer,List(class MyActor, <function0>))

scala> Typed[MyActor].create("Bernd")
res1: de.knutwalker.akka.typed.ActorRef[MyMessage] = Actor[akka://foo/user/$a#1452982654]

scala> ActorOf(Typed[MyActor].props("Bernd"), "typed-bernd")
res2: de.knutwalker.akka.typed.package.ActorRef[MyMessage] = Actor[akka://foo/user/typed-bernd#1482052715]

Wrong invocations are greeted with a compile error instead of a runtime error!

scala> Typed[MyActor].create()
<console>:26: error: type mismatch;
 found   : shapeless.HNil
 required: shapeless.::[String,shapeless.HNil]
       Typed[MyActor].create()
                            ^

scala> Typed[MyActor].create("Bernd", "Ralf")
<console>:26: error: type mismatch;
 found   : shapeless.::[String("Bernd"),shapeless.::[String("Ralf"),shapeless.HNil]]
 required: shapeless.::[String,shapeless.HNil]
       Typed[MyActor].create("Bernd", "Ralf")
                            ^

scala> Typed[MyActor].create(42)
<console>:26: error: type mismatch;
 found   : shapeless.::[Int(42),shapeless.HNil]
 required: shapeless.::[String,shapeless.HNil]
       Typed[MyActor].create(42)
                            ^

Hooray, Benefit!

As you can see, shapeless leaks in the error messages, but you can still easily see what parameters are wrong.
This technique uses whitebox macros under the hood, which means that support from IDEs such as IntelliJ will be meager, so prepare for red, squiggly lines.
If you open autocomplete on a Typed[MyActor], you won’t see the create or props methods but createProduct and propsProduct. This is a leaky implementation as well, better just ignore it and type against those IDE errors.

The next bits are about the internals and some good pratices..

» Implementation Notes