How do I get array item type in TypeScript using the Reflection API? - arrays

I have the following little class in TypeScript, with some public fields decorated:
class Company {
#dataMember
public name: string;
#dataMember
public people: Person[];
}
class Person {
// ...
}
By using reflect metadata, I can determine the types of Company properties name and people: they are the constructor functions String and Array, respectively, which is expected and logical.
My property decorator function:
function decorate(target: Object, propertyKey: string | symbol): void {
var reflectType = Reflect.getMetadata("design:type", target, propertyKey);
// ...
}
But how could I determine the type (constructor function) of array elements? Is it even possible? In the above example, it should be (a reference to) Person.
Note: I need the type reference before instantiation, and because of this, it is impossible to dynamically determine the type using array items: there are no array items, there isn't even an Array instance.

I don't think this is possible as of now. If you see the generated js file, for array of anything, it creates metadata with type as Array without any information on type.
__decorate([
dataMember_1.dataMember,
__metadata('design:type', Array)
], Company.prototype, "people", void 0);
For built-in types, one way I could think of solving this problem is to pass the type in the decorator itself and writing the custom logic in the decorator code.
#dataMember(String)
myProp: Array<String>
For Custom objects, most of the time when the decorator call is fired, the module is not fully loaded. So, one way is to pass the class name and parse it later.
#dataMember("People")
people: People[]

Related

Why does TypeScript allow overloading return type as 'any' when implementing interfaces

I am trying to determine why TypeScript allows you to overload the return type of a function to the type 'any' from a more specific type when implementing an interface.
In my case I am working in Angular and am injecting the implemented class.
My environment:
Visual Studio 2017
Angular Version 1.5.5
TypeScript Version 2.1.5
The following code compiles without any issue:
export interface IFoo {
thing: (parameter: number) => string;
}
export class BarService implements IFoo {
public thing = (parameter: number): any => {
return { "whatever": parameter };
}
}
angular.module("FooBar").service("barService", BarService);
So now when I attempt to consume the IFoo interface and am expecting a string to be returned from the 'thing' function call the compiler actually allows it to happen!
export class Whatever {
public foo: IFoo;
public myString: string;
static $inject = ["barService"];
constructor(barService: IFoo) {
this.foo = barService;
this.myString = this.foo.thing(0);
}
}
It seems that TypeScript should fail to compile when the return type is overloaded with type 'any' because consumers of the interface are expecting a strongly typed object.
Here is what I have put together.
From https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.1:
All types in TypeScript are subtypes of a single top type called the
Any type. The any keyword references this type. The Any type is the
one type that can represent any JavaScript value with no constraints.
And also:
The Any type is used to represent any JavaScript value. A value of the
Any type supports the same operations as a value in JavaScript and
minimal static type checking is performed for operations on Any
values. Specifically, properties of any name can be accessed through
an Any value and Any values can be called as functions or constructors
with any argument list.
Playing around:
interface IPerson {
name: string
}
class Person implements IPerson {
name: any;
}
// Error
//class Person2 implements IPerson {
// name: number;
//}
const person: Person = new Person();
person.name = 3;
let x: number = 3;
x = <any>"hello"; // Works!
//x = "hello"; // Error
We can see in even a simple example above that any can be used to override the type system which follows the docs.
My belief is that this behavior is there to allow the flexibility of javascript's untyped (flexible) behavior.
I'm not an expert on Typescript but based on my understanding of any:
https://www.typescriptlang.org/docs/handbook/basic-types.html
We find this comment on that page:
"We want to opt-out of type-checking and let the values pass through compile-time checks."
So I'm guessing when the compilers sees any, it says "I will not confirm this type". Ergo this condition must be sufficient for the compiler to assume that the function has been implemented correctly.
I used to think of any as "accept anything" (which is does). But more precisely it means "Assume this is the type you want.", from what I've seen. So in this case the compiler assumes it is string for your convenience and allows the compile-time check to pass.
As i see it there are two places that you could expect TypeScript compiler to fail. BarService returning any and Whatever class assigning return value from thing() function to myString.
The compiler doesn't fail when you return any in your BarService because in TypeScript you can use any as a substitude for any/all Types. The type any in TypeScript is mainly thought of to make it easier to support old javascript libraries or code. Check the Any section here: https://www.typescriptlang.org/docs/handbook/basic-types.html. And yes can and is abused.
The compiler doesn't fail in your Whatever class because here you are using the interface that in fact does says that the thing() function returns a string. The compiler do not know about the BarService when compiling the Whatever class.

What is <T> in dynamic forms?

Im following the Angular2 cookbook recipe for Dynamic Forms. It calls for
export class QuestionBase<T>{
value: T,
...
I cant seem to find out what the is doing in both spots. Any ideas?
Those are so called "Generics". You may just google for the term "generics", for example in combination with "typescript", in order to get a more detailed answer.
The quick version is:
with generics you do not care which type T is - as long as it is the same type everywhere you use it.
So an instance of
QuestionBase<String>
has to make sure that the property "value" is of type String
The T on the QuestionBase<T> stands for Type.
This means that whatever type you enter in the <> that is the type that value will have.
So,
If T = string:
export class QuestionBase<string>{
value: string,
If T = int:
export class QuestionBase<int>{
value: int,
If T = any:
export class QuestionBase<any>{
value: any,
If T = any[]:
export class QuestionBase<any[]>{
value: any[],
T here makes your class a template..which means your class can be of any type
while creating the object of QuestionBase you can say like below
var obj=new QuestionBase<string>();
now here your value property will be of string type.
Similarly
var obj=new QuestionBase<int>(); value property will of type int here.

Convert String into an object instance name

I'm trying to turn an string into an instance name.
stage.focus = ["box_"+[i+1]];
this gives me back = box_2;
but I need it to be an object not a string.
In as2 I could use eval. How do I do it in as3?
The correct syntax is:
this["box_"+(i+1)]
For example if you would like to call the function "start" in your main class, you'd do it this way:
this["start"]();
Same thing goes for variables. Since all classes are a subclass of Object you can retrieve their variables like you would with an ordinary object. A class like this:
package{
import flash.display.Sprite;
public class Main extends Sprite{
public var button:Sprite;
public function Main(){
trace(this["button"]);
}
}
}
Would output:
[object Sprite]
If you want to access a member of the current class, the answers already given will work. But if the instance you are looking isn't part of the class, you are out of luck.
For example:
private function foo():void {
var box_2:Sprite;
trace(this["box_"+(i+1)]);
}
Won't work, because box_2 isn't a part of the class. In that case, it is highly recommended to use an array.
If you want to access a DisplayObject (for example, a Sprite or a MovieClip) you also can use getChildByName. But in that case, box_2 will be the name of the object, instead of the name of the variable. You set the name like
var box:Sprite;
box.name = "box_2";
But again, I recommend an array.

Creating New Array with Class Object in GWT

I would like to create a new array with a given type from a class object in GWT.
What I mean is I would like to emulate the functionality of
java.lang.reflect.Array.newInstance(Class<?> componentClass, int size)
The reason I need this to occur is that I have a library which occasionally needs to do the following:
Class<?> cls = array.getClass();
Class<?> cmp = cls.getComponentType();
This works if I pass it an array class normally, but I can't dynamically create a new array from some arbitrary component type.
I am well aware of GWT's lack of reflection; I understand this. However, this seems feasible even given GWT's limited reflection. The reason I believe this is that in the implementation, there exists an inaccessible static method for creating a class object for an array.
Similarly, I understand the array methods to just be type-safe wrappers around JavaScript arrays, and so should be easily hackable, even if JSNI is required.
In reality, the more important thing would be getting the class object, I can work around not being able to make new arrays.
If you are cool with creating a seed array of the correct type, you can use jsni along with some knowledge of super-super-source to create arrays WITHOUT copying through ArrayList (I avoid java.util overhead like the plague):
public static native <T> T[] newArray(T[] seed, int length)
/*-{
return #com.google.gwt.lang.Array::createFrom([Ljava/lang/Object;I)(seed, length);
}-*/;
Where seed is a zero-length array of the correct type you want, and length is the length you want (although, in production mode, arrays don't really have upper bounds, it makes the [].length field work correctly).
The com.google.gwt.lang package is a set of core utilities used in the compiler for base emulation, and can be found in gwt-dev!com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang.
You can only use these classes through jsni calls, and only in production gwt code (use if GWT.isProdMode()). In general, if you only access the com.google.gwt.lang classes in super-source code, you are guaranteed to never leak references to classes that only exist in compiled javascript.
if (GWT.isProdMode()){
return newArray(seed, length);
}else{
return Array.newInstance(seed.getComponentType(), length);
}
Note, you'll probably need to super-source the java.lang.reflect.Array class to avoid gwt compiler error, which suggests you'll want to put your native helper method there. However, I can't help you more than this, as it would overstep the bounds of my work contract.
The way that I did a similar thing was to pass an empty, 0 length array to the constructor of the object that will want to create the array from.
public class Foo extends Bar<Baz> {
public Foo()
{
super(new Baz[0]);
}
...
}
Baz:
public abstract class Baz<T>
{
private T[] emptyArray;
public Baz(T[] emptyArray)
{
this.emptyArray = emptyArray;
}
...
}
In this case the Bar class can't directly create new T[10], but we can do this:
ArrayList<T> al = new ArrayList<T>();
// add the items you want etc
T[] theArray = al.toArray(emptyArray);
And you get your array in a typesafe way (otherwise in your call super(new Baz[0]); will cause a compiler error).
I had to do something similar, I found it was possible using the Guava library's ObjectArrays class. Instead of the class object it requires a reference to an existing array.
T[] newArray = ObjectArrays.newArray(oldArray, oldArray.length);
For implementing an array concatenation method, I also stepped into the issue of missing Array.newInstance-method.
It's still not implemented, but if you have an existing array you can use
Arrays.copyOf(T[] original, int newLength)
instead.

Can someone explain the magic going on in Prism's resolve<> method?

I've got a CustomersModule.cs with the following Initialize() method:
public void Initialize()
{
container.RegisterType<ICustomersRepository, CustomersRepository>(new ContainerControlledLifetimeManager());
CustomersPresenter customersPresenter = this.container.Resolve<CustomersPresenter>();
}
The class I resolve from the container looks like this:
class CustomersPresenter
{
private CustomersView view;
private ICustomersRepository customersRespository;
public CustomersPresenter(CustomersView view,
ICustomersRepository customersRepository,
TestWhatever testWhatever)
{
this.view = view;
this.customersRespository = customersRepository;
}
}
The TestWhatever class is just a dummy class I created:
public class TestWhatever
{
public string Title { get; set; }
public TestWhatever()
{
Title = "this is the title";
}
}
Yet the container happily resolves CustomersPresenter even though I never registered it, and also the container somehow finds TestWhatever, instantiates it, and injects it into CustomersPresenter.
I was quite surprised to realize this since I couldn't find anywhere in the Prism documentation which explicitly stated that the container was so automatic.
So this is great, but it what else is the container doing that I don't know about i.e. what else can it do that I don't know about? For example, can I inject classes from other modules and if the modules happen to be loaded the container will inject them, and if not, it will inject a null?
There is nothing magical going on. You are specifying concrete types, so naturally they are resolvable, because if we have the Type object, we can call a constructor on it.
class Fred { };
Fred f1 = new Fred();
Type t = typeof(Fred);
Fred f2 = (Fred)t.GetConstructor(Type.EmptyTypes).Invoke(null);
The last line above is effectively what happens, the type t having been found by using typeof on the type parameter you give to Resolve.
If the type cannot be constructed by new (because it's in some unknown separate codebase) then you wouldn't be able to give it as a type parameter to Resolve.
In the second case, it is constructor injection, but it's still a known concrete constructable type. Via reflection, the Unity framework can get an array of all the Types of the parameters to the constructor. The type TestWhatever is constructable, so there is no ambiguity or difficulty over what to construct.
As to your concern about separate modules (assemblies), if you move TestWhatever to another assembly, that will not change the lines of code you've written; it will just mean that you have to add a reference to the other assembly to get this one to build. And then TestWhatever is still an unambiguously refeferenced constructable type, so it can be constructed by Unity.
In other words, if you can refer to the type in code, you can get a Type object, and so at runtime it will be directly constructable.
Response to comment:
If you delete the class TestWhatever, you will get a compile-time error, because you refer to that type in your code. So it won't be possible to get a runtime by doing that.
The decoupling is still in effect in this arrangement, because you could register a specific instance of TestWhatever, so every call to Resolve<TestWhatever>() will get the same instance, rather than constructing a new one.
The reason this works is because Unity is designed for it. When you Resolve with a concrete type, Unity looks to see if it can resolve from the container. If it cannot, then it just goes and instantiates the type resolving it's dependencies. It's really quite simple.

Resources