Can We Cast a Generic Object to a Custom Object Type in JavaScript

Casting plain objects to class instances in javascript

Creating an object in JavaScript requires the invocation of its constructor. So, at first you will need to find the correct arguments, which may not always be just properties. After that, you can reassign all public properties from the JSON-parsed object to the created instances.

A general solution would be that every constructor accepts any objects that look like instances (including real instances) and clones them. All the internal logic needed to create proper instances will be located in the right place then.

Or even better than overloading the constructor might be to create a static method on your class that takes objects and creates instances from them:

Person.fromJSON = function(obj) {
// custom code, as appropriate for Person instances
// might invoke `new Person`
return …;
};

Your case is very simple, as you don't have any arguments and only public properties. To change {personName:John,animals:[]} to an object instance, use this:

var personLiteral = ... // JSON.parse("...");
var personInstance = new Person();
for (var prop in personLiteral)
personInstance[prop] = personLiteral[prop];

You can also use Object.assign functionality (or e.g. jQuery.extend pre-ES6) for this:

var personInstance = Object.assign(new Person(), personLiteral);

The creation of the Animal instances works analogous.

As JSON does not transport any information about the classes, you must know the structure before. In your case it will be:

var persons = JSON.parse(serverResponse);
for (var i=0; i<persons.length; i++) {
persons[i] = $.extend(new Person, persons[i]);
for (var j=0; j<persons[i].animals; j++) {
persons[i].animals[j] = $.extend(new Animal, persons[i].animals[j]);
}
}

Btw, your run methods seems likely to be added on the Animal.prototype object instead of each instance.

Instantiation of generic type to support custom objects

calling new Edge(...) will not create any subclass of Edge represented as E unless E really does represent Edge. Java does not change the actual type of an object when you cast it from one type to another, let alone when you cast it to a generic type. For a cast to a specific type to work, the object itself must already be that type.

if you want to create a new E, maybe you can pass it a Supplier<E> or use a factory pattern to create a new E properly.

Cast Object to Generic Type for returning

You have to use a Class instance because of the generic type erasure during compilation.

public static <T> T convertInstanceOfObject(Object o, Class<T> clazz) {
try {
return clazz.cast(o);
} catch(ClassCastException e) {
return null;
}
}

The declaration of that method is:

public T cast(Object o)

This can also be used for array types. It would look like this:

final Class<int[]> intArrayType = int[].class;
final Object someObject = new int[]{1,2,3};
final int[] instance = convertInstanceOfObject(someObject, intArrayType);

Note that when someObject is passed to convertToInstanceOfObject it has the compile time type Object.

TypeScript object type casting, when the two objects differ by key name(s)

Don't overthink it:

function backendToLibrary(input: TagTypeThatMyBackendWants): TagTypeThatALibraryWants {
return {
id: input.id,
text: input.name
}
}

It's tempting to look at a problem like this, especially if you need to do it many times and think: perhaps there's an abstraction here.

But ultimately you know how properties map, so if you were to use/write a generic mapping utility, you would still need to configure this utility for each specific case, ultimately resulting in something that's more complex then if you literally just wrote it out for each case.

Unless I'm missing a use-case, I don't think there's a benefit to doing something more complicated.

Cast object to interface in TypeScript

There's no casting in javascript, so you cannot throw if "casting fails".

Typescript supports casting but that's only for compilation time, and you can do it like this:

const toDo = <IToDoDto> req.body;
// or
const toDo = req.body as IToDoDto;

You can check at runtime if the value is valid and if not throw an error, i.e.:

function isToDoDto(obj: any): obj is IToDoDto {
return typeof obj.description === "string" && typeof obj.status === "boolean";
}

@Post()
addToDo(@Response() res, @Request() req) {
if (!isToDoDto(req.body)) {
throw new Error("invalid request");
}

const toDo = req.body as IToDoDto;
this.toDoService.addToDo(toDo);
return res.status(HttpStatus.CREATED).end();
}

Edit

As @huyz pointed out, there's no need for the type assertion because isToDoDto is a type guard, so this should be enough:

if (!isToDoDto(req.body)) {
throw new Error("invalid request");
}

this.toDoService.addToDo(req.body);

How do I cast a JSON Object to a TypeScript class?

You can't simple cast a plain-old-JavaScript result from an Ajax request into a prototypical JavaScript/TypeScript class instance. There are a number of techniques for doing it, and generally involve copying data. Unless you create an instance of the class, it won't have any methods or properties. It will remain a simple JavaScript object.

While if you only were dealing with data, you could just do a cast to an interface (as it's purely a compile time structure), this would require that you use a TypeScript class which uses the data instance and performs operations with that data.

Some examples of copying the data:

  1. Copying AJAX JSON object into existing Object
  2. Parse JSON String into a Particular Object Prototype in JavaScript

In essence, you'd just :

var d = new MyRichObject();
d.copyInto(jsonResult);


Related Topics



Leave a reply



Submit