JSON-Object를 사용하여 TypeScript 개체를 초기화하려면 어떻게 해야 합니까?
REST 서버에 대한 AJAX 콜로부터 JSON 오브젝트를 수신했다.이 개체에는 내 TypeScript 클래스와 일치하는 속성 이름이 있습니다(이 질문에 대한 후속 조치입니다).
초기화하는 가장 좋은 방법은 무엇입니까?클래스(& JSON 오브젝트)에는 클래스인 오브젝트 및 멤버의 리스트인 멤버가 있고, 이러한 클래스에는 리스트 및/또는 클래스인 멤버가 있기 때문에 이 작업은 동작하지 않을 것입니다.
단, 멤버명을 검색하여 할당하고, 필요에 따라 리스트를 작성하고, 클래스를 인스턴스화함으로써, 모든 클래스의 멤버에 대해 명시적인 코드를 작성할 필요가 없습니다(LOT가 많이 있습니다).
다음은 몇 가지 다른 방법을 보여 주는 몇 가지 간단한 장면입니다.그들은 결코 "완전"하지 않으며, 면책 사항으로서, 저는 이렇게 하는 것이 좋은 생각이라고 생각하지 않습니다.그리고 코드를 빠르게 입력해서 깔끔하지 않아요.
메모로서도:물론 역직렬화 가능한 클래스는 디폴트 컨스트럭터를 가질 필요가 있습니다.다른 모든 언어에서 그렇듯이 모든 종류의 역직렬화를 인식하고 있습니다.물론 Javascript는 디폴트 이외의 컨스트럭터를 인수 없이 호출해도 불평하지 않지만, 클래스는 그때 대비하는 것이 좋습니다(게다가, 실제로는 「타이프 스크립트 방식」이 아닙니다).
옵션 1: 런타임 정보가 전혀 없음
이 접근법의 문제는 대부분 멤버의 이름이 클래스와 일치해야 한다는 것입니다.이로 인해 클래스당 동일한 유형의 멤버 1명으로 제한되고 몇 가지 모범 사례 규칙이 위반됩니다.저는 이에 대해 강력히 반대합니다만, 제가 이 답변을 썼을 때의 첫 번째 "초안"이었기 때문에 여기에 기재해 주십시오(따라서 이름은 "Foo" 등).
module Environment {
export class Sub {
id: number;
}
export class Foo {
baz: number;
Sub: Sub;
}
}
function deserialize(json, environment, clazz) {
var instance = new clazz();
for(var prop in json) {
if(!json.hasOwnProperty(prop)) {
continue;
}
if(typeof json[prop] === 'object') {
instance[prop] = deserialize(json[prop], environment, environment[prop]);
} else {
instance[prop] = json[prop];
}
}
return instance;
}
var json = {
baz: 42,
Sub: {
id: 1337
}
};
var instance = deserialize(json, Environment, Environment.Foo);
console.log(instance);
옵션 2:이름 속성
옵션 #1의 문제를 해결하려면 JSON 객체의 노드 유형에 대한 정보가 필요합니다.문제는 Typescript에서 이것들은 컴파일 시간 구성이며 런타임에 필요합니다.그러나 런타임 오브젝트는 설정될 때까지 그 속성을 인식하지 못합니다.
그것을 하는 한 가지 방법은 학급들이 그들의 이름을 알게 하는 것이다.JSON에도 이 자산이 필요합니다.실제로는 json에만 필요합니다.
module Environment {
export class Member {
private __name__ = "Member";
id: number;
}
export class ExampleClass {
private __name__ = "ExampleClass";
mainId: number;
firstMember: Member;
secondMember: Member;
}
}
function deserialize(json, environment) {
var instance = new environment[json.__name__]();
for(var prop in json) {
if(!json.hasOwnProperty(prop)) {
continue;
}
if(typeof json[prop] === 'object') {
instance[prop] = deserialize(json[prop], environment);
} else {
instance[prop] = json[prop];
}
}
return instance;
}
var json = {
__name__: "ExampleClass",
mainId: 42,
firstMember: {
__name__: "Member",
id: 1337
},
secondMember: {
__name__: "Member",
id: -1
}
};
var instance = deserialize(json, Environment);
console.log(instance);
옵션 3: 멤버유형을 명시적으로 기술한다.
위에서 설명한 바와 같이 클래스 멤버의 유형 정보는 런타임에 사용할 수 없습니다.즉, 클래스 멤버의 유형 정보는 사용할 수 없습니다.우리는 이것을 비원시적인 멤버에게만 하면 되고 우리는 갈 수 있다.
interface Deserializable {
getTypes(): Object;
}
class Member implements Deserializable {
id: number;
getTypes() {
// since the only member, id, is primitive, we don't need to
// return anything here
return {};
}
}
class ExampleClass implements Deserializable {
mainId: number;
firstMember: Member;
secondMember: Member;
getTypes() {
return {
// this is the duplication so that we have
// run-time type information :/
firstMember: Member,
secondMember: Member
};
}
}
function deserialize(json, clazz) {
var instance = new clazz(),
types = instance.getTypes();
for(var prop in json) {
if(!json.hasOwnProperty(prop)) {
continue;
}
if(typeof json[prop] === 'object') {
instance[prop] = deserialize(json[prop], types[prop]);
} else {
instance[prop] = json[prop];
}
}
return instance;
}
var json = {
mainId: 42,
firstMember: {
id: 1337
},
secondMember: {
id: -1
}
};
var instance = deserialize(json, ExampleClass);
console.log(instance);
옵션 4:장황하지만 깔끔한 방법
2016년 01월 03일 갱신: @GameAlchemist가 코멘트(아이디어, 구현)에서 지적한 바와 같이 Typescript 1.7에서는 클래스/프로퍼티 데코레이터를 사용하여 아래 솔루션을 보다 효율적으로 작성할 수 있습니다.
연재는 항상 문제이며, 내 생각에 가장 좋은 방법은 가장 짧지 않은 방법입니다.모든 옵션 중에서 클래스 작성자가 역직렬화된 객체의 상태를 완전히 제어할 수 있기 때문에 이 옵션을 선호합니다.굳이 추측하자면, 조만간 다른 모든 옵션이 당신을 곤란하게 할 것입니다(Javascript가 이 문제에 대한 네이티브 방법을 생각해내지 않는 한).
실제로 다음 예에서는 유연성이 제대로 발휘되지 않습니다.수업 구조를 그대로 베끼는 거죠.그러나 여기서 기억해야 할 차이점은 클래스 전체가 제어하고 싶은 모든 종류의 JSON을 사용할 수 있다는 것입니다(계산할 수 있는 등).
interface Serializable<T> {
deserialize(input: Object): T;
}
class Member implements Serializable<Member> {
id: number;
deserialize(input) {
this.id = input.id;
return this;
}
}
class ExampleClass implements Serializable<ExampleClass> {
mainId: number;
firstMember: Member;
secondMember: Member;
deserialize(input) {
this.mainId = input.mainId;
this.firstMember = new Member().deserialize(input.firstMember);
this.secondMember = new Member().deserialize(input.secondMember);
return this;
}
}
var json = {
mainId: 42,
firstMember: {
id: 1337
},
secondMember: {
id: -1
}
};
var instance = new ExampleClass().deserialize(json);
console.log(instance);
하면 .Object.assign
언제 추가되었는지는 모르겠지만, 현재 Typescript 2.0.2를 사용하고 있으며, ES6 기능인 것 같습니다.
client.fetch( '' ).then( response => {
return response.json();
} ).then( json => {
let hal : HalJson = Object.assign( new HalJson(), json );
log.debug( "json", hal );
★★★★★★★★★★★★★★★★★.HalJson
export class HalJson {
_links: HalLinks;
}
export class HalLinks implements Links {
}
export interface Links {
readonly [text: string]: Link;
}
export interface Link {
readonly href: URL;
}
크롬은 이렇게 말한다
HalJson {_links: Object}
_links
:
Object
public
:
Object
href
:
"http://localhost:9000/v0/public
재귀적으로 할당되지 않는 것을 알 수 있습니다.
TLDR: Type JSON (개념 실증 작업)
이 문제의 근본 원인은 컴파일 시에만 존재하는 유형 정보를 사용하여 런타임에 JSON을 역직렬화해야 한다는 것입니다.이를 위해서는 어떤 식으로든 런타임에 유형 정보를 사용할 수 있어야 합니다.
다행히 이 문제는 데코레이터와 리플렉트 데코레이터를 통해 매우 우아하고 견고한 방법으로 해결할 수 있습니다.
- 속성 데코레이터를 사용하여 메타데이터 정보를 기록하고 클래스 프로토타입 등에 해당 정보를 저장합니다.
- 이 메타데이터 정보를 재귀 이니셜라이저(디시리얼라이저)에 공급합니다.
기록 유형 정보
ReflectDecorator와 속성디코이터의 조합을 사용하면 특성에 대한 유형 정보를 쉽게 기록할 수 있습니다.이 접근방식의 기본적인 실장은 다음과 같습니다.
function JsonMember(target: any, propertyKey: string) {
var metadataFieldKey = "__propertyTypes__";
// Get the already recorded type-information from target, or create
// empty object if this is the first property.
var propertyTypes = target[metadataFieldKey] || (target[metadataFieldKey] = {});
// Get the constructor reference of the current property.
// This is provided by TypeScript, built-in (make sure to enable emit
// decorator metadata).
propertyTypes[propertyKey] = Reflect.getMetadata("design:type", target, propertyKey);
}
합니다.__propertyTypes__
츠미야예를 들어 다음과 같습니다.
class Language {
@JsonMember // String
name: string;
@JsonMember// Number
level: number;
}
class Person {
@JsonMember // String
name: string;
@JsonMember// Language
language: Language;
}
이것으로 런타임에 필요한 유형 정보를 처리할 수 있게 되었습니다.
유형 정보 처리
'우리에게 필요한 것'을 얻어야 .Object
JSON.parse
후, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아__propertyTypes__
(상기 참조) 및 그에 따라 필요한 속성을 인스턴스화합니다.루트 객체의 유형을 지정해야 합니다.그러면 디시리얼라이저에 시작점이 생깁니다.
이 접근방식의 간단한 실장은 다음과 같습니다.
function deserialize<T>(jsonObject: any, Constructor: { new (): T }): T {
if (!Constructor || !Constructor.prototype.__propertyTypes__ || !jsonObject || typeof jsonObject !== "object") {
// No root-type with usable type-information is available.
return jsonObject;
}
// Create an instance of root-type.
var instance: any = new Constructor();
// For each property marked with @JsonMember, do...
Object.keys(Constructor.prototype.__propertyTypes__).forEach(propertyKey => {
var PropertyType = Constructor.prototype.__propertyTypes__[propertyKey];
// Deserialize recursively, treat property type as root-type.
instance[propertyKey] = deserialize(jsonObject[propertyKey], PropertyType);
});
return instance;
}
var json = '{ "name": "John Doe", "language": { "name": "en", "level": 5 } }';
var person: Person = deserialize(JSON.parse(json), Person);
위의 아이디어는 JSON에 존재하는 것이 아니라 예상되는 유형(복소수/객체 값)에 따라 역직렬화된다는 큰 이점이 있습니다.만약 a가Person
되어 있는 「」, 「」입니다.Person
생성된 인스턴스.원시 유형 및 어레이에 대한 몇 가지 추가 보안 조치를 취하면 이 접근 방식을 안전하게 하여 악의적인 JSON을 방지할 수 있습니다.
엣지
그러나 솔루션이 매우 간단하다는 사실에 만족하셨다면 몇 가지 나쁜 소식이 있습니다. 처리해야 할 수많은 엣지 케이스가 있다는 것입니다.그 중 일부만 다음과 같습니다.
- 어레이 및 어레이 요소(특히 중첩된 어레이)
- 다형성
- 추상 클래스 및 인터페이스
- ...
만약 이 모든 것을 만지작거리고 싶지 않다면, 저는 기꺼이 이 접근방식을 이용한 개념 실증 버전을 추천합니다.Type JSON은 제가 매일 직면하는 문제인 이 문제에 대처하기 위해 만든 것입니다.
데코레이터는 아직 실험적인 존재이기 때문에 제작에 사용하는 것을 추천하고 싶지 않지만, 지금까지는 도움이 되었습니다.
TypeScript 하는 툴을 툴은 "TypeScript"의 결과에 런타임 체크를 합니다.JSON.parse
: ts.quicktype.이오
예를 들어 다음 JSON이 지정됩니다.
{
"name": "David",
"pets": [
{
"name": "Smoochie",
"species": "rhino"
}
]
}
quicktype은 다음 TypeScript 인터페이스 및 유형 맵을 생성합니다.
export interface Person {
name: string;
pets: Pet[];
}
export interface Pet {
name: string;
species: string;
}
const typeMap: any = {
Person: {
name: "string",
pets: array(object("Pet")),
},
Pet: {
name: "string",
species: "string",
},
};
다음 .JSON.parse
'이것'은 다음과 같습니다.
export function fromJson(json: string): Person {
return cast(JSON.parse(json), object("Person"));
}
코드를 몇 개 빠뜨렸습니다만, 자세한 것은 퀵 타이프를 사용해 주세요.
https://github.com/weichx/cerialize이라는 사람을 고용하고 있습니다.
매우 간단하지만 강력합니다.지원 대상:
- 오브젝트 트리 전체의 시리얼화 및 시리얼화 해제.
- 같은 오브젝트상의 영속성 및 일시적인 속성.
- 시리얼화 로직을 커스터마이즈하기 위한 훅.
- 기존 인스턴스로 직렬화(비직렬화)하거나(Angular에 매우 적합합니다) 새 인스턴스를 생성할 수 있습니다.
- 기타.
예:
class Tree {
@deserialize public species : string;
@deserializeAs(Leaf) public leafs : Array<Leaf>; //arrays do not need extra specifications, just a type.
@deserializeAs(Bark, 'barkType') public bark : Bark; //using custom type and custom key name
@deserializeIndexable(Leaf) public leafMap : {[idx : string] : Leaf}; //use an object as a map
}
class Leaf {
@deserialize public color : string;
@deserialize public blooming : boolean;
@deserializeAs(Date) public bloomedAt : Date;
}
class Bark {
@deserialize roughness : number;
}
var json = {
species: 'Oak',
barkType: { roughness: 1 },
leafs: [ {color: 'red', blooming: false, bloomedAt: 'Mon Dec 07 2015 11:48:20 GMT-0500 (EST)' } ],
leafMap: { type1: { some leaf data }, type2: { some leaf data } }
}
var tree: Tree = Deserialize(json, Tree);
단순한 오브젝트의 경우 다음 방법이 좋습니다.
class Person {
constructor(
public id: String,
public name: String,
public title: String) {};
static deserialize(input:any): Person {
return new Person(input.id, input.name, input.title);
}
}
var person = Person.deserialize({id: 'P123', name: 'Bob', title: 'Mr'});
생성자에서 속성을 정의하는 기능을 활용하면 간결해질 수 있습니다.
이렇게 하면 Object.assign 또는 오브젝트를 사용하는 모든 응답과 비교하여 외부 라이브러리나 데코레이터가 필요하지 않습니다.
저의 접근방식은 다음과 같습니다(매우 간단합니다).
const jsonObj: { [key: string]: any } = JSON.parse(jsonStr);
for (const key in jsonObj) {
if (!jsonObj.hasOwnProperty(key)) {
continue;
}
console.log(key); // Key
console.log(jsonObj[key]); // Value
// Your logic...
}
만약 당신이 타입의 안전을 원하고 장식가가 싫다면
abstract class IPerson{
name?: string;
age?: number;
}
class Person extends IPerson{
constructor({name, age}: IPerson){
super();
this.name = name;
this.age = age;
}
}
const json = {name: "ali", age: 80};
const person = new Person(json);
또는 내가 좋아하는 것
class Person {
constructor(init?: Partial<Person>){
Object.assign(this, init);
}
name?: string;
age?: number;
}
const json = {name: "ali", age: 80};
const person = new Person(json);
옵션 5: Typescript 컨스트럭터와 jQuery.extend 사용
이것이 가장 유지보수가 쉬운 방법인 것 같습니다.json 구조를 파라미터로 하는 컨스트럭터를 추가하고 json 객체를 확장합니다.이렇게 하면 json 구조를 전체 애플리케이션 모델로 해석할 수 있습니다.
인터페이스를 만들거나 생성자에 속성을 나열할 필요가 없습니다.
export class Company
{
Employees : Employee[];
constructor( jsonData: any )
{
jQuery.extend( this, jsonData);
// apply the same principle to linked objects:
if ( jsonData.Employees )
this.Employees = jQuery.map( jsonData.Employees , (emp) => {
return new Employee ( emp ); });
}
calculateSalaries() : void { .... }
}
export class Employee
{
name: string;
salary: number;
city: string;
constructor( jsonData: any )
{
jQuery.extend( this, jsonData);
// case where your object's property does not match the json's:
this.city = jsonData.town;
}
}
급여를 계산하기 위해 회사를 받는 Ajax 콜백:
onReceiveCompany( jsonCompany : any )
{
let newCompany = new Company( jsonCompany );
// call the methods on your newCompany object ...
newCompany.calculateSalaries()
}
이 목적을 위해 찾은 가장 좋은 것은 클래스 트랜스포머입니다.
사용법은 다음과 같습니다.
일부 클래스:
export class Foo {
name: string;
@Type(() => Bar)
bar: Bar;
public someFunction = (test: string): boolean => {
...
}
}
// the docs say "import [this shim] in a global place, like app.ts"
import 'reflect-metadata';
// import this function where you need to use it
import { plainToClass } from 'class-transformer';
export class SomeService {
anyFunction() {
u = plainToClass(Foo, JSONobj);
}
}
「 」를하고 있는 는,@Type
이치노
위에서 설명한 네 번째 옵션은 간단하고 좋은 방법입니다.멤버 슈퍼클래스의 서브클래스의 발생 중 하나인 멤버리스트와 같은 클래스 계층을 처리해야 하는 경우(예를 들어 Director extensions Member 또는 Student extends Member 등)에는 두 번째 옵션과 조합해야 합니다.이 경우 서브클래스 유형을 json 형식으로 지정해야 합니다.
JQuery .extend는 다음을 수행합니다.
var mytsobject = new mytsobject();
var newObj = {a:1,b:2};
$.extend(mytsobject, newObj); //mytsobject will now contain a & b
팩토리를 사용한 다른 옵션
export class A {
id: number;
date: Date;
bId: number;
readonly b: B;
}
export class B {
id: number;
}
export class AFactory {
constructor(
private readonly createB: BFactory
) { }
create(data: any): A {
const createB = this.createB.create;
return Object.assign(new A(),
data,
{
get b(): B {
return createB({ id: data.bId });
},
date: new Date(data.date)
});
}
}
export class BFactory {
create(data: any): B {
return Object.assign(new B(), data);
}
}
https://github.com/MrAntix/ts-deserialize
이렇게 사용하다
import { A, B, AFactory, BFactory } from "./deserialize";
// create a factory, simplified by DI
const aFactory = new AFactory(new BFactory());
// get an anon js object like you'd get from the http call
const data = { bId: 1, date: '2017-1-1' };
// create a real model from the anon js object
const a = aFactory.create(data);
// confirm instances e.g. dates are Dates
console.log('a.date is instanceof Date', a.date instanceof Date);
console.log('a.b is instanceof B', a.b instanceof B);
- 수업을 단순하게 유지하다
- 공장들이 유연성을 위해 사용할 수 있는 주입
저는 개인적으로 @Ingo Burk의 3번 옵션을 선호합니다.복잡한 데이터와 원시 데이터의 배열을 지원하도록 코드를 개선했습니다.
interface IDeserializable {
getTypes(): Object;
}
class Utility {
static deserializeJson<T>(jsonObj: object, classType: any): T {
let instanceObj = new classType();
let types: IDeserializable;
if (instanceObj && instanceObj.getTypes) {
types = instanceObj.getTypes();
}
for (var prop in jsonObj) {
if (!(prop in instanceObj)) {
continue;
}
let jsonProp = jsonObj[prop];
if (this.isObject(jsonProp)) {
instanceObj[prop] =
types && types[prop]
? this.deserializeJson(jsonProp, types[prop])
: jsonProp;
} else if (this.isArray(jsonProp)) {
instanceObj[prop] = [];
for (let index = 0; index < jsonProp.length; index++) {
const elem = jsonProp[index];
if (this.isObject(elem) && types && types[prop]) {
instanceObj[prop].push(this.deserializeJson(elem, types[prop]));
} else {
instanceObj[prop].push(elem);
}
}
} else {
instanceObj[prop] = jsonProp;
}
}
return instanceObj;
}
//#region ### get types ###
/**
* check type of value be string
* @param {*} value
*/
static isString(value: any) {
return typeof value === "string" || value instanceof String;
}
/**
* check type of value be array
* @param {*} value
*/
static isNumber(value: any) {
return typeof value === "number" && isFinite(value);
}
/**
* check type of value be array
* @param {*} value
*/
static isArray(value: any) {
return value && typeof value === "object" && value.constructor === Array;
}
/**
* check type of value be object
* @param {*} value
*/
static isObject(value: any) {
return value && typeof value === "object" && value.constructor === Object;
}
/**
* check type of value be boolean
* @param {*} value
*/
static isBoolean(value: any) {
return typeof value === "boolean";
}
//#endregion
}
// #region ### Models ###
class Hotel implements IDeserializable {
id: number = 0;
name: string = "";
address: string = "";
city: City = new City(); // complex data
roomTypes: Array<RoomType> = []; // array of complex data
facilities: Array<string> = []; // array of primitive data
// getter example
get nameAndAddress() {
return `${this.name} ${this.address}`;
}
// function example
checkRoom() {
return true;
}
// this function will be use for getting run-time type information
getTypes() {
return {
city: City,
roomTypes: RoomType
};
}
}
class RoomType implements IDeserializable {
id: number = 0;
name: string = "";
roomPrices: Array<RoomPrice> = [];
// getter example
get totalPrice() {
return this.roomPrices.map(x => x.price).reduce((a, b) => a + b, 0);
}
getTypes() {
return {
roomPrices: RoomPrice
};
}
}
class RoomPrice {
price: number = 0;
date: string = "";
}
class City {
id: number = 0;
name: string = "";
}
// #endregion
// #region ### test code ###
var jsonObj = {
id: 1,
name: "hotel1",
address: "address1",
city: {
id: 1,
name: "city1"
},
roomTypes: [
{
id: 1,
name: "single",
roomPrices: [
{
price: 1000,
date: "2020-02-20"
},
{
price: 1500,
date: "2020-02-21"
}
]
},
{
id: 2,
name: "double",
roomPrices: [
{
price: 2000,
date: "2020-02-20"
},
{
price: 2500,
date: "2020-02-21"
}
]
}
],
facilities: ["facility1", "facility2"]
};
var hotelInstance = Utility.deserializeJson<Hotel>(jsonObj, Hotel);
console.log(hotelInstance.city.name);
console.log(hotelInstance.nameAndAddress); // getter
console.log(hotelInstance.checkRoom()); // function
console.log(hotelInstance.roomTypes[0].totalPrice); // getter
// #endregion
실제는 아니지만 간단한 솔루션:
interface Bar{
x:number;
y?:string;
}
var baz:Bar = JSON.parse(jsonString);
alert(baz.y);
어려운 의존관계에도 대응합니다!!!
당신은 아래와 같이 할 수 있다.
export interface Instance {
id?:string;
name?:string;
type:string;
}
그리고.
var instance: Instance = <Instance>({
id: null,
name: '',
type: ''
});
나의 접근법은 조금 다르다.속성을 새 인스턴스에 복사하지 않고 기존 POJO의 프로토타입을 변경할 뿐입니다(이전 브라우저에서는 잘 작동하지 않을 수 있습니다).각 클래스는 하위 개체의 프로토타이프를 설정하기 위한 SetProtypes 메서드를 제공해야 하며, 이러한 메서드는 자체 SetProtype 메서드를 제공합니다.
(_Type 속성을 사용하여 알 수 없는 객체의 클래스 이름을 가져오지만 여기서는 무시해도 됩니다.)
class ParentClass
{
public ID?: Guid;
public Child?: ChildClass;
public ListOfChildren?: ChildClass[];
/**
* Set the prototypes of all objects in the graph.
* Used for recursive prototype assignment on a graph via ObjectUtils.SetPrototypeOf.
* @param pojo Plain object received from API/JSON to be given the class prototype.
*/
private static SetPrototypes(pojo: ParentClass): void
{
ObjectUtils.SetPrototypeOf(pojo.Child, ChildClass);
ObjectUtils.SetPrototypeOfAll(pojo.ListOfChildren, ChildClass);
}
}
class ChildClass
{
public ID?: Guid;
public GrandChild?: GrandChildClass;
/**
* Set the prototypes of all objects in the graph.
* Used for recursive prototype assignment on a graph via ObjectUtils.SetPrototypeOf.
* @param pojo Plain object received from API/JSON to be given the class prototype.
*/
private static SetPrototypes(pojo: ChildClass): void
{
ObjectUtils.SetPrototypeOf(pojo.GrandChild, GrandChildClass);
}
}
ObjectUtils.ts는 다음과 같습니다.
/**
* ClassType lets us specify arguments as class variables.
* (where ClassType == window[ClassName])
*/
type ClassType = { new(...args: any[]): any; };
/**
* The name of a class as opposed to the class itself.
* (where ClassType == window[ClassName])
*/
type ClassName = string & {};
abstract class ObjectUtils
{
/**
* Set the prototype of an object to the specified class.
*
* Does nothing if source or type are null.
* Throws an exception if type is not a known class type.
*
* If type has the SetPrototypes method then that is called on the source
* to perform recursive prototype assignment on an object graph.
*
* SetPrototypes is declared private on types because it should only be called
* by this method. It does not (and must not) set the prototype of the object
* itself - only the protoypes of child properties, otherwise it would cause a
* loop. Thus a public method would be misleading and not useful on its own.
*
* https://stackoverflow.com/questions/9959727/proto-vs-prototype-in-javascript
*/
public static SetPrototypeOf(source: any, type: ClassType | ClassName): any
{
let classType = (typeof type === "string") ? window[type] : type;
if (!source || !classType)
{
return source;
}
// Guard/contract utility
ExGuard.IsValid(classType.prototype, "type", <any>type);
if ((<any>Object).setPrototypeOf)
{
(<any>Object).setPrototypeOf(source, classType.prototype);
}
else if (source.__proto__)
{
source.__proto__ = classType.prototype.__proto__;
}
if (typeof classType["SetPrototypes"] === "function")
{
classType["SetPrototypes"](source);
}
return source;
}
/**
* Set the prototype of a list of objects to the specified class.
*
* Throws an exception if type is not a known class type.
*/
public static SetPrototypeOfAll(source: any[], type: ClassType): void
{
if (!source)
{
return;
}
for (var i = 0; i < source.length; i++)
{
this.SetPrototypeOf(source[i], type);
}
}
}
사용방법:
let pojo = SomePlainOldJavascriptObjectReceivedViaAjax;
let parentObject = ObjectUtils.SetPrototypeOf(pojo, ParentClass);
// parentObject is now a proper ParentClass instance
**model.ts**
export class Item {
private key: JSON;
constructor(jsonItem: any) {
this.key = jsonItem;
}
}
**service.ts**
import { Item } from '../model/items';
export class ItemService {
items: Item;
constructor() {
this.items = new Item({
'logo': 'Logo',
'home': 'Home',
'about': 'About',
'contact': 'Contact',
});
}
getItems(): Item {
return this.items;
}
}
언급URL : https://stackoverflow.com/questions/22885995/how-do-i-initialize-a-typescript-object-with-a-json-object
'sourcecode' 카테고리의 다른 글
워드프레스가 올바른 코멘트 파일을 사용하지 않습니까? (0) | 2023.02.07 |
---|---|
@font-face 새로 고침 시 Chrome에서 텍스트가 표시되지 않음...항상 그렇지는 않아? (0) | 2023.02.07 |
Configuration Builder를 사용한 기본 경로 설정 (0) | 2023.02.07 |
JSON 오더 혼재 (0) | 2023.02.07 |
WooCommerce가 프로그래밍 방식으로 주문을 작성하고 지불로 리디렉션합니다. (0) | 2023.02.07 |