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:
- Copying AJAX JSON object into existing Object
- Parse JSON String into a Particular Object Prototype in JavaScript
In essence, you'd just :
var d = new MyRichObject();
d.copyInto(jsonResult);
Related Topics
How to Combine Object Values from Separate Lines into One Line
Search Bar With Dropdown Results
How to Add Query String Parameter to Same Url When on Click a Href Link
Charts.Js Graph Not Scaling to Canvas Size
What Is the Purpose of the Dollar Sign in JavaScript
Merge Array of Objects by Same Key-Value
React Typescript Is Not Assignable to Parameter of Type
How to Show an Alert After Reloading the Page in JavaScript
If a Div Contains a Specific String of Text, Edit the Parent'S CSS
Detect If String Contains Any Spaces
Setting Cross-Domain Cookies in Safari
Onclick Table Row With Onclick Button and Bootstrap Modal Inside
Textarea With Initial Auto Height by Content With Pure CSS
Filter Input Text to Enter Only Number and Not Even Decimal
Javascript Validation: Block Special Characters
Refresh the Parent Component View in Angular 4