TypeScript: Factory method - incorrect extends, types returned incompatible - typescript-generics

Again spending way too much time with correct typings and was wondering whether such thing is possible without compiler throwing error of incorrect base class extension, even tho it correctly recognizes returned type (see the last line):
class Parent {
static create<T extends Parent>(Cls: new () => T): T {
return new Cls();
}
}
class Child extends Parent {
static create() {
return super.create(Child);
}
}
const inst = Child.create(); // correct type of "Child"
Playground Link
Error thrown:
Class static side 'typeof Child' incorrectly extends base class static side 'typeof Parent'.
The types returned by 'create(...)' are incompatible between these types.
Type 'Child' is not assignable to type 'T'.
'Child' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Parent'.
How to tell compiler, that returned type will be the same type as Cls parameter? I'm kinda newbie in TS, but I'd say I don't need generics as I have the type of the created object passed as parameter, so I know exactly the type.

Over here TypeScript compiler is trying to match up the two static methods. Even though you are ensuring that the return types match up, Typescript doesn't know that for sure. You can think of it in a way where each distinct invocation of Parent::create creates a different method in Parent. One for Child which extends for Parent, but there could be AnotherChild that extends from Parent. And Child could be not assignable to the other subtype and that's why the compiler complains.
I believe it'd be just easier to remove the generic code and do something like -
class Parent {
static create(Cls: new () => Parent): Parent {
return new Cls();
}
}
class Child extends Parent {
static create() : Child {
return super.create(Child);
}
}
const inst = Child.create(); // correct type of "Child"
As Child is already extending from Parent, Child::create over here is perfectly valid now.

Related

Is instance property of Firebase a function?

https://pub.dev/documentation/firebase_messaging/latest/firebase_messaging/FirebaseMessaging/instance.html
static FirebaseMessaging get instance
{
return FirebaseMessaging._(app: Firebase.app());
}
instance word here does not have () after it, but it has {}.
Even while calling it we use: FirebaseMessaging.instance. No brackets.
Is this a function or something else?
There is 2 things to understand why you can call FirebaseMessaging.instance:
Getter
FirebaseMessaging get instance { /* ... */ }
First thing to understand is the concept of a getter defined by the keyword get. A getter is a method which does not take any arguments and which returns a value. In this case you have a getter named instance which returns an object of type FirebaseMessaging.
So a getter is technically a function which could also be written like this:
FirebaseMessaging getInstance() { /* ... */ }
But a getter is supposedly faster as it is dedicated to only retrieve values.
Static method
Now how can you have access to this getter/method without needing an instance of the FirebaseMessaging object ? Well, it is simply because of the static keyword used for the getter:
static FirebaseMessaging get instance { /* ... */ }
Any method or variable declared within a class with the static keyword is the same for every instance of this class. Basically a single copy of this method will be shared among all instances of the FirebaseMessaging class. It allocates memory only once at the class loading.
So by calling FirebaseMessaging.instance you are calling a static method.

Is there more neat design for requesting static fields in class successors?

I'm implementing network controller that sends requests to the server with integer command type id and binary serialized block of other command data. Prototype of all commands looks like:
class NetCommand {
public static var typeId; // type must be set in successors!
function new() {
}
public function typeGet():Int {
return Reflect.field(Type.getClass(this), "typeId");
}
}
All this mess in typeGet() function done just for access to the static variables with type ids of all successors. I can't simply write
return typeId;
because statics are not inheritable and this method will return 0 as a value of prototype's variable. Is there any neat solution? Is my solution cross-platform?
Update:
All command classes must be registered in controller class like this:
public function bindResponse(aClass:Class<NetCommand>) {
var typeId = Reflect.field(aClass, "typeId");
mBindResponse.set(typeId, aClass);
}
and then when new command arrives its data passes to the method that find necessary class by command id, creates instance of desired class and passes other data to it:
function onResponse(aTypeId:Int, aData:Dynamic) {
var cmdClass:Class<NetCommand> = mBindResponse.get(aTypeId);
var command:NetCommand = Type.createInstance(cmdClass, []);
command.response(aData); // this must be overriden in successor classes
}
Method typeGet() is used only for targeting outgoing instances and error handling with default behaviour of error command class without creating a heap of classes that differs only by typeId constant. So this method suppreses implementation of the real command id and may be overriden for example.
Why don't you simply make typeId an instance member (not static) ?

Dynamic Instantiate in Dart

I need an object that makes instances of other objects. I want the ability to pass in the class of the objects being created, but they all need to have the same type, and it would be great if they could all start out with the same values:
class Cloner{
BaseType prototype;
BaseType getAnother(){
BaseType newthing = prototype.clone(); //but there's no clone() in Dart
newthing.callsomeBaseTypeMethod();
return newthing;
}
}
So, prototype could be set to any object that is of type BaseClass, even if it's something whose class is a subclass of BaseClass. I'm sure there's a way to do this with the mirrors library, but I just wanted to make sure I'm not missing some obvious built-in factory way to do it.
I could see how this could be set up with a generic: Cloner<T>, but then there's no way that we can make sure T is a subtype of BaseType at compile-time, right?
To get you started, you can create a small "constructor" function that returns new instances. Try this:
typedef BaseType Builder();
class Cloner {
Builder builder;
Cloner(Builder builder);
BaseType getAnother() {
BaseType newthing = builder();
newthing.callsomeBaseTypeMethod();
return newthing;
}
}
main() {
var cloner = new Cloner(() => new BaseType());
var thing = cloner.getAnother();
}
In the above code, we create a typedef to define a function that returns a BaseType.

static constants return instance of specific class in Flex?

So here's what I mean.
Let's say I have a class ErrorMessages which holds all my error messages as static constants. So I could access them like ErrorMessages.PASSWORD_INVALID or ErrorMessage.PASSWORD_TOO_SHORT. I want to know if it is possible to have separate classes that hold subset of these constants and access them like ErrorMessages.PASSWORD.INVALID or ErrorMessages.PASSWORD.TOO_SHORT, etc.
This way I can more structured static structure and makes it much easier to use autocomplete.
I tried few different ways and couldn't figure out if this was possible..
Declare them as const Objects in the static class - you won't get them in auto complete though.
public class ErrorMessages
{
public static const PASSWORD:Object = {
INVALID:"invalid password",
TOO_SHORT:"minimum 6 chars required",
TOO_LONG:"100 chars: r u sure?"
};
public static const FILE:Object = {
NOT_FOUND:"No such file",
READ_ONLY:"it is readonly",
SOMETHING_ELSE:"something else"
};
}
trace(ErrorMessages.PASSWORD.INVALID);
If auto complete is important, create a dedicated com.domain.errors package and declare different classes for different categories of errors (like PASSWORD, FILE etc) within that package. Now declare public static constants inside those classes as appropriate.
or if you want to keep a single class, you can define classes, inside your Error class. You might would like to have those text coming from properties file. So, you can make use of resourceManager instance and get the text from specific resource bundle.
--
http://riageeks.com
Here's what I end up doing
package com.domain.data.type {
public class ErrorMessages {
public static function get PASSWORD:PasswordErrorMessages { return new PasswordErrorMessages(); }
}
}
class PasswordErrorMessages {
public function get INVALID():String { return "invalid password"; }
}
This way I can get the behavior I wanted: ErrorMessages.PASSWORD.INVALID with autocomplete. It's not as clean as I'd like it to be.. but I guess this will do.

Strange behavior from getDefinitionByName

I've created a class that loads it's subclasses based on a name passed to it. The function uses getDefinitionByName, gets the class type, and instantiates it, and returns it if the class is a subtype of the class that owns this method. The subtypes are all mxml files that extend the base class, in order to simplify instantiating controls.
However, in the case where I pass it a fully qualified name, it works in my unit tests but fails when I execute it in the context of my application. Is there a gotcha in getDefinitionByName that makes it behave differently in different execution contexts? Is there a simpler way to load classes by their qualified name?
static public function loadDisplay(className:String, extendedClassName:String = null):FeatureDisplay
{
try
{
trace("Loading", className);
var cls:Class = getDefinitionByName(className) as Class;
var display:FeatureDisplay = new cls() as FeatureDisplay;
if(display)
{
return display;
}
else
{
trace(className, "is not a subclass of FeatureDisplay");
return null;
}
}
catch(error:Error)
{
trace("Error loading", className);
trace("Error:", error.message);
}
return null;
}
My first question is are you explicitly using any of the classes anywhere? If you do not actually use a class, even if it is imported, ActionScript may not end up keeping a copy of the class's definition in the swf.
That said, you're better off avoiding getDefinitionByName, describeType, getQualifiedClassName or getQualifiedSuperclassName if you can possibly avoid them. They are memory hogs and it is generally best to avoid them. (unless you do not have control over which classes will be used at run time and they HAVE to be used through getDefinitionByName).
My suggestion is that you replace getQualifiedClassName with a swtich...case:
// Import the subclasses.
import path.to.SpriteFeatureDisplay;
import path.to.OtherFeatureDisplay;
class FeatureDisplay extends Sprite{
//Make one public static const per class.
public static const SPRITE_FEATURE_DISPLAY:String = "sprite_feature_display";
public static const OTHER_FEATURE_DISPLAY:String = "other_feature_display";
public static function loadDisplay( className:String,
extName:String = null ):FeatureDisplay
{
trace("Loading", className);
// This will ensure that each of the classes is stored in the swf
// it will behave faster, and it is less prone to errors (note that
// try...catch is not needed).
swtich( className )
{
case SPRITE_FEATURE_DISPLAY:
return new SpriteFeatureDisplay();
case OTHER_FEATURE_DISPLAY:
return new OtherFeatureDisplay();
default:
trace( "Requested class " + className + " could not be created..." +
"\nPlease make sure that it is a subclass of FeatureDisplay" );
return null;
}
return null;
}
}
FYI, I've seen the following method of keeping classes used in Flex's source code:
// References.cs
// notice the double reference: one to import, the other to reference
import package.to.ClassA; ClassA;
import package.to.ClassB; ClassB;
import package.to.ClassC; ClassC;
Of course, you still have to reference the "References" class somewhere.

Resources