Désérialiser des objets depuis le JSON vers des entités typées en Typescript est un besoin que l'on peut rencontrer n'importe quand.
Voici ce que je fais de mon côté, afin de pouvoir profiter pleinement des méthodes de mes objets.
Pour un objet simple, ceci suffit :
export class Identity {
public name: string;
public age: number;
public constructor(init?: Partial<Identity>) {
Object.assign(this, init);
}
}
Dès que l'on commence à avoir des collections, il faut ajouter un peu d'intelligence (on part du principe que la classe Adress aura un constructeur qui permet cette initialisation, voir dessous) :
export class Contact {
public adresses: Address[];
public phone: string;
public constructor(init?: Partial<Contact >) {
Object.assign(this, init);
if (init != null) {
this.adresses= init.adresses== null ? [] : init.adresses.map(it => new Address(it));
}
}
}
export class Address{
public city: string;
public constructor(init?: Partial<Address>) {
Object.assign(this, init);
}
}
Si on a des "nested objects", donc des classes qui ont d'autres classes en attribut, on fait comme ceci :
export class Person {
public identity: Identity;
public contact: Contact;
public constructor(init?: Partial<Person>) {
Object.assign(this, init);
if (init != null) {
this.identity= init.identity== null ? null : new Identity(init.identity);
this.contact= init.contact== null ? null : new Contact(init.contact);
}
}
}
Et enfin, comment on s'en sert - dans les grandes lignes (passke quand même, hein !):
return this.http.get(`/api/person/${personId}`)
.toPromise()
.then((response: any) => new Person(JSON.parse(response)) );
ENFIN !!!
BON SANG JE LA CHERCHAIS CETTE FEATURE ! <3
class Person {
public name: string = "default"
public address: string = "default"
public age: number = 0;
public constructor(init?:Partial<Person>) {
Object.assign(this, init);
}
public printSomething() {
return 'toto is ' + this.name;
}
}
let persons = [
new Person(),
new Person({}),
new Person({name:"John"}),
new Person({address:"Earth"}),
new Person({age:20, address:"Earth", name:"John"})
];
console.log(new Person({name:"John"}).printSomething());
// => toto is John
console.log(new Person({name:"John"}).constructor.name);
// => person
Je dois encore le travailler mais c'est un début de réflexion.
Objectif : utiliser la classe de cette manière :
RomanNumber toto = new RomanNumber(5);
System.out.println(toto.toString());
Dans le cas ou l'on souhaite une représentation textuelle, bien sûr.
import java.util.LinkedList;
import java.util.List;
public class RomanNumber {
private List<RomanCharacter> characters;
public RomanNumber(int arabicNumber) {
this.characters = new LinkedList<>();
this.convertArabicNumberToRomanNumber(arabicNumber);
}
private void convertArabicNumberToRomanNumber(int arabicNumber) {
int remains = arabicNumber;
for (RomanCharacter currentCharacter : RomanCharacter.getOrderedRomanNumbers()) {
while (this.arabicNumberIsGreaterThanRomanNumber(remains, currentCharacter)) {
this.characters.add(currentCharacter);
remains = remains - currentCharacter.toInt();
}
if (remains == 0) {
break;
}
}
}
private boolean arabicNumberIsGreaterThanRomanNumber(int arabicNumber, RomanCharacter romanNumber) {
return arabicNumber > 0 && arabicNumber >= romanNumber.toInt();
}
public String toString() {
StringBuilder textualVersion = new StringBuilder(this.characters.size());
for (RomanCharacter character : this.characters) {
textualVersion.append(character.toString());
}
return textualVersion.toString();
}
}
import java.util.*;
public enum RomanCharacter {
M(1000), CM(900), D(500), CD(400), C(100), XC(90), L(50), XL(40), X(10), IX(9), V(5), IV(4), I(1);
private final int correspondingArabicNumber;
RomanCharacter(int arabicNumber) {
this.correspondingArabicNumber = arabicNumber;
}
public int toInt() {
return this.correspondingArabicNumber;
}
public String toString() {
return this.name();
}
public static List<RomanCharacter> getOrderedRomanNumbers() {
return Arrays.asList(RomanCharacter.values());
}
}