I personally think this is fine, as long as you are absolutely sure you are casting to the correct type - I have seen a few other Haxe libraries (such as minject) use this approach.
With Haxe, you can use type parameters like so:
var c:Map<String,BaseComponent>;
public function getComponent<T:BaseComponent>( name:String, type:Class<T> ):T {
if ( components.exists(name) ) {
var c = components[name];
if ( Std.is(c, type) ) {
return cast c;
}
}
return null; // the component with that name didn't exist, or was the wrong type
}
This way your usage can be:
var transform = componentManager.getComponent( "transform", TransformComponent );
if ( transform!=null ) {
transform.doSomething();
}
In this case, transform will be fully typed as a "TransformComponent" and the compiler will let you access all of it's methods etc.
On a final note, if you only ever have one instance of each type of component, you could make this even easier:
public function addComponent<T:BaseComponent>( component:T ) {
var type = Type.getClass( component );
var name = Type.getClassName( type );
components[name] = component;
}
public function getComponent<T:BaseComponent>( type:Class<T> ):T {
var name = Type.getClassName( type );
return cast components[name]; // Either the component with the correct type name, or null.
}
componentManager.addComponent( new TransformComponent() );
var t = componentManager.get( TransformComponent );
$type( t ); // TransformComponent, it is correctly typed