2

I currently have a function that needs to accept a class type, instantiate the class and return the INSTANCE, of a template type. I am getting an error: 'ActorType' only refers to a type, but is being used as a value here.

spawnActor<ActorType extends Actor>(actorClass: typeof ActorType): ActorType {
    let actorObject = new actorClass();
    actorObject.sayHello(); // specific to Actor
    return actorObject;
}

Currently I found that the declaration works if I make the parameter type not using the template, actorClass: Actor rather than actorClass: ActorType. However when the function is called I have to specify the template type explicitly as it can't be inferred from the class passed into the actorClass parameter.

spawnActor<ActorType extends Actor>(actorClass: typeof Actor): ActorType {
    let actorObject = (new actorClass() as ActorType); // must cast to template type
    actorObject.sayHello(); // specific to Actor
    return actorObject;
}

let a = spawnActor<MyActorClass>(MyActorClass); // have to give template type for a to have correct type
//let a = spawnActor(MyActorClass); // ideally it would be inferred
J. Doe
  • 77
  • 1
  • 6

1 Answers1

2

The typeof operator doesn't get the constructor of a class in general; it gets the type of a value with a certain name. The confusion you're having is that classes declared with class Foo {} create both a type named Foo (the instance type of the class) and a value named Foo (the constructor for the class), and then typeof Foo is the type of that value. But with the generic type parameter ActorType, there is no value named ActorType for you to get the type with typeof ActorType... and even if there were such a value there'd be little chance it would turn out to be the constructor of ActorType instances. The distinction between types and values is important and confusing and I've talked at length about this before.

What you're really looking for is a "newable" call signature. If your instance type is T, then a constructor of no arguments which produces an instance of T has type:

new() => T;

or equivalently:

{ new(): T }

If you use new() => ActorType instead of typeof ActorType you should be able to make this work. Hope that helps; good luck!

jcalz
  • 264,269
  • 27
  • 359
  • 360