JSON 개체를 TypeScript 클래스에 캐스트하려면 어떻게 해야 합니까?
원격 REST 서버에서 JSON 개체를 읽었습니다.이 JSON 개체는 (설계상) 타이프스크립트 클래스의 모든 속성을 가집니다.JSON 객체를 수신한 유형을 VAR로 캐스팅하려면 어떻게 해야 합니까?
typscript var(즉, 이 JSON 개체를 사용하는 생성자가 있음)를 채우지 않습니다.크기가 커서 서브오브젝트 및 속성별로 서브오브젝트 전체에서 모든 것을 복사하는 데 시간이 많이 걸립니다.
업데이트: 그러나 타이프스크립트 인터페이스에 캐스팅할 수 있습니다!
Ajax 요청의 플레인-old-JavaScript 결과를 프로토타입의 JavaScript/TypeScript 클래스 인스턴스에 간단히 캐스트할 수 없습니다.여기에는 많은 기술이 있으며 일반적으로 데이터 복사가 포함됩니다.클래스의 인스턴스를 만들지 않으면 메서드나 속성이 없습니다.단순한 JavaScript 개체로 남습니다.
데이터만 다루는 경우 인터페이스에 캐스트만 하면 됩니다(순수하게 컴파일 시간 구조이기 때문에). 이렇게 하려면 데이터 인스턴스를 사용하고 해당 데이터로 작업을 수행하는 TypeScript 클래스를 사용해야 합니다.
데이터 복사 예:
요점은 다음과 같습니다.
var d = new MyRichObject();
d.copyInto(jsonResult);
저도 같은 문제가 있었고, https://github.com/pleerock/class-transformer라는 기능을 하는 라이브러리를 찾았습니다.
다음과 같이 동작합니다.
let jsonObject = response.json() as Object;
let fooInstance = plainToClass(Models.Foo, jsonObject);
return fooInstance;
중첩된 하위 항목을 지원하지만 클래스 구성원을 장식해야 합니다.
TypeScript에서는 다음과 같은 인터페이스와 제네릭을 사용하여 유형 어설션을 수행할 수 있습니다.
var json = Utilities.JSONLoader.loadFromFile("../docs/location_map.json");
var locations: Array<ILocationMap> = JSON.parse(json).location;
여기서 ILocationMap은 데이터의 모양을 나타냅니다.이 방법의 장점은 JSON이 더 많은 속성을 포함할 수 있지만 셰이프가 인터페이스의 조건을 충족한다는 것입니다.
단, 클래스 인스턴스 메서드는 추가되지 않습니다.
ES6 를 사용하고 있는 경우는, 다음과 같이 시험해 주세요.
class Client{
name: string
displayName(){
console.log(this.name)
}
}
service.getClientFromAPI().then(clientData => {
// Here the client data from API only have the "name" field
// If we want to use the Client class methods on this data object we need to:
let clientWithType = Object.assign(new Client(), clientData)
clientWithType.displayName()
})
그러나 안타깝게도 이 방법은 중첩된 개체에서는 작동하지 않습니다.
JSON의 Typescript 클래스에 대한 일반 캐스팅에 대한 매우 흥미로운 기사를 발견했습니다.
http://cloudmark.github.io/Json-Mapping/
다음과 같은 코드가 표시됩니다.
let example = {
"name": "Mark",
"surname": "Galea",
"age": 30,
"address": {
"first-line": "Some where",
"second-line": "Over Here",
"city": "In This City"
}
};
MapUtils.deserialize(Person, example); // custom class
서버로부터 수신한 JSON 오브젝트에 예상된 타입 스크립트의 인터페이스 속성이 있는지(읽기에 적합한지) 아직 자동으로 확인할 수 있는 것은 없습니다.그러나 사용자 정의 유형 가드를 사용할 수 있습니다.
다음 인터페이스와 어리석은 json 오브젝트(임의의 타입일 가능성이 있습니다)를 고려합니다.
interface MyInterface {
key: string;
}
const json: object = { "key": "value" }
3가지 방법:
A. 변수 뒤에 배치되는 Assertion 또는 단순 정적 캐스트 유형
const myObject: MyInterface = json as MyInterface;
B. 변수 앞과 다이아몬드 사이의 단순한 정적 주조
const myObject: MyInterface = <MyInterface>json;
C. 어드밴스드 다이내믹 캐스트, 객체의 구조를 직접 확인합니다.
function isMyInterface(json: any): json is MyInterface {
// silly condition to consider json as conform for MyInterface
return typeof json.key === "string";
}
if (isMyInterface(json)) {
console.log(json.key)
}
else {
throw new Error(`Expected MyInterface, got '${json}'.`);
}
점은 이 글을 입니다.isMyInterface기능.TS가 조만간 데코레이터를 추가하여 복잡한 타이핑을 런타임에 내보내고 필요할 때 런타임에 오브젝트의 구조를 체크해 주었으면 합니다.현재 용도가 거의 동일한 json 스키마 검증기를 사용하거나 이 런타임 유형 검사 함수 생성기를 사용할 수 있습니다.
TLDR: 라이너 1개
// This assumes your constructor method will assign properties from the arg.
.map((instanceData: MyClass) => new MyClass(instanceData));
상세한 답변
Object.assign 접근법은 클래스 자체에서 선언되지 않은 관련 없는 속성(및 정의된 폐쇄)으로 클래스 인스턴스를 부적절하게 흐트러뜨릴 수 있으므로 권장하지 않습니다.
역직렬화하려는 클래스에서 역직렬화하려는 속성이 정의되어 있는지 확인합니다(늘, 빈 배열 등).초기값으로 속성을 정의하면 값을 할당할 클래스 멤버를 반복할 때 속성을 확인할 수 있습니다(아래의 역직렬화 방법 참조).
export class Person {
public name: string = null;
public favoriteSites: string[] = [];
private age: number = null;
private id: number = null;
private active: boolean;
constructor(instanceData?: Person) {
if (instanceData) {
this.deserialize(instanceData);
}
}
private deserialize(instanceData: Person) {
// Note this.active will not be listed in keys since it's declared, but not defined
const keys = Object.keys(this);
for (const key of keys) {
if (instanceData.hasOwnProperty(key)) {
this[key] = instanceData[key];
}
}
}
}
위의 예에서는 단순히 역직렬화 방법을 만들었습니다.실제 예에서는 재사용 가능한 기본 클래스 또는 서비스 방식으로 중앙 집중화합니다.
다음은 http response와 같은 방법으로 사용하는 방법입니다.
this.http.get(ENDPOINT_URL)
.map(res => res.json())
.map((resp: Person) => new Person(resp) ) );
가 인수 하는 경우 각 tslint/ide를 합니다.<YourClassName> : :
const person = new Person(<Person> { name: 'John', age: 35, id: 1 });
특정 유형의 클래스 멤버(다른 클래스의 인스턴스라고도 함)가 있는 경우 getter/setter 메서드를 사용하여 해당 멤버를 입력된 인스턴스에 캐스트할 수 있습니다.
export class Person {
private _acct: UserAcct = null;
private _tasks: Task[] = [];
// ctor & deserialize methods...
public get acct(): UserAcct {
return this.acct;
}
public set acct(acctData: UserAcct) {
this._acct = new UserAcct(acctData);
}
public get tasks(): Task[] {
return this._tasks;
}
public set tasks(taskData: Task[]) {
this._tasks = taskData.map(task => new Task(task));
}
}
위의 예에서는 acct와 작업 목록을 모두 해당 클래스 인스턴스로 역직렬화합니다.
json의 속성이 typescript 클래스와 동일하다고 가정하면 Json 속성을 typescript 객체에 복사할 필요가 없습니다.생성자의 json 데이터를 전달하는 Typescript 객체를 생성하기만 하면 됩니다.
Ajax 콜백에서 다음과 같은 회사를 받습니다.
onReceiveCompany( jsonCompany : any )
{
let newCompany = new Company( jsonCompany );
// call the methods on your newCompany object ...
}
이를 실현하기 위해:
typescript 합니다.1) typescript json은 typescript를 합니다.에서는 jQuery를 jQuery는 jQuery를 사용합니다.$.extend( this, jsonData) $.할 수 있습니다. $.120을 사용하면 json 객체의 속성을 추가하는 동안 Javascript 프로토타입을 유지할 수 있습니다.
2) 링크된 오브젝트에 대해서도 같은 작업을 수행해야 합니다.예제에서 Employees의 경우 직원의 json 데이터 부분을 차지하는 생성자도 만듭니다.$.map을 호출하여 json 종업원을 typescript Employee 객체로 변환할 수 있습니다.
export class Company
{
Employees : Employee[];
constructor( jsonData: any )
{
$.extend( this, jsonData);
if ( jsonData.Employees )
this.Employees = $.map( jsonData.Employees , (emp) => {
return new Employee ( emp ); });
}
}
export class Employee
{
name: string;
salary: number;
constructor( jsonData: any )
{
$.extend( this, jsonData);
}
}
이것은 Typescript 클래스와 json 객체를 다룰 때 찾은 최고의 솔루션입니다.
내 경우에는 효과가 있다.Object.assign 함수(타깃, 소스...)를 사용했습니다.먼저 올바른 개체를 생성한 다음 json 개체에서 타겟으로 데이터를 복사합니다.예:
let u:User = new User();
Object.assign(u , jsonUsers);
보다 고도의 사용 예도 있습니다.어레이를 사용하는 예.
this.someService.getUsers().then((users: User[]) => {
this.users = [];
for (let i in users) {
let u:User = new User();
Object.assign(u , users[i]);
this.users[i] = u;
console.log("user:" + this.users[i].id);
console.log("user id from function(test it work) :" + this.users[i].getId());
}
});
export class User {
id:number;
name:string;
fullname:string;
email:string;
public getId(){
return this.id;
}
}
캐스팅 자체는 아니지만, 저는 https://github.com/JohnWhiteTB/TypedJSON이 유용한 대안이라는 것을 발견했습니다.
@JsonObject
class Person {
@JsonMember
firstName: string;
@JsonMember
lastName: string;
public getFullname() {
return this.firstName + " " + this.lastName;
}
}
var person = TypedJSON.parse('{ "firstName": "John", "lastName": "Doe" }', Person);
person instanceof Person; // true
person.getFullname(); // "John Doe"
개인적으로 typescript가 엔드포인트 정의를 통해 수신되는 객체의 유형을 지정할 수 없는 것은 끔찍합니다.이것이 사실인 것 같기 때문에 다른 언어에서도 마찬가지로 클래스 정의에서 JSON 개체를 분리하여 클래스 정의에서 JSON 개체를 유일한 데이터 멤버로 사용합니다.
저는 보일러 플레이트 코드를 싫어하기 때문에 타입을 유지하면서 최소한의 코드로 원하는 결과를 얻는 것이 보통입니다.
다음 JSON 객체 구조 정의를 고려해 보십시오. 이러한 정의는 엔드포인트에서 수신할 수 있습니다. 구조 정의일 뿐 메서드는 없습니다.
interface IAddress {
street: string;
city: string;
state: string;
zip: string;
}
interface IPerson {
name: string;
address: IAddress;
}
위의 내용을 오브젝트 지향 용어로 생각하면 위의 인터페이스는 데이터 구조만 정의하기 때문에 클래스가 아닙니다.OO 용어로 된 클래스는 데이터와 해당 클래스에서 작동하는 코드를 정의합니다.
이제 데이터를 지정하는 클래스와 해당 클래스에서 동작하는 코드를 정의합니다.
class Person {
person: IPerson;
constructor(person: IPerson) {
this.person = person;
}
// accessors
getName(): string {
return person.name;
}
getAddress(): IAddress {
return person.address;
}
// You could write a generic getter for any value in person,
// no matter how deep, by accepting a variable number of string params
// methods
distanceFrom(address: IAddress): float {
// Calculate distance from the passed address to this persons IAddress
return 0.0;
}
}
이제 우리는 아이퍼슨 구조에 맞는 어떤 물체든 그냥 통과해서 갈 수 있어
Person person = new Person({
name: "persons name",
address: {
street: "A street address",
city: "a city",
state: "a state",
zip: "A zipcode"
}
});
같은 방법으로, 우리는 당신의 끝점에서 받은 오브젝트를 다음과 같은 방법으로 처리할 수 있습니다.
Person person = new Person(req.body); // As in an object received via a POST call
person.distanceFrom({ street: "Some street address", etc.});
이는 성능이 훨씬 향상되어 데이터를 복사하는 데 절반의 메모리를 사용하는 동시에 각 엔티티 유형에 대해 작성해야 하는 보일러 플레이트 코드의 양을 대폭 줄입니다.이는 단순히 TypeScript가 제공하는 유형의 안전성에 의존합니다.
인터페이스에서 확장 클래스를 사용합니다.
그 후, 다음과 같이 입력합니다.
Object.assign(
new ToWhat(),
what
)
그리고 가장 좋은 점:
Object.assign(
new ToWhat(),
<IDataInterface>what
)
ToWhat가 DataInterface
그할 수 있는 json typescript를 해야 .Object.setPrototypeOf「 」 「 」 、 「 」
Object.setPrototypeOf(jsonObject, YourTypescriptClass.prototype)
'as' 선언 사용:
const data = JSON.parse(response.data) as MyClass;
대부분 정답이지만 효율적인 답변은 아닌 오래된 질문입니다.제가 제안하는 것은 다음과 같습니다.
init() 메서드와 스태틱캐스트 메서드를 포함하는 기본 클래스를 만듭니다(단일 개체 및 배열용).static 메서드는 어디에나 사용할 수 있습니다.기본 클래스와 init()를 사용하는 버전에서는 나중에 쉽게 확장할 수 있습니다.
export class ContentItem {
// parameters: doc - plain JS object, proto - class we want to cast to (subclass of ContentItem)
static castAs<T extends ContentItem>(doc: T, proto: typeof ContentItem): T {
// if we already have the correct class skip the cast
if (doc instanceof proto) { return doc; }
// create a new object (create), and copy over all properties (assign)
const d: T = Object.create(proto.prototype);
Object.assign(d, doc);
// reason to extend the base class - we want to be able to call init() after cast
d.init();
return d;
}
// another method casts an array
static castAllAs<T extends ContentItem>(docs: T[], proto: typeof ContentItem): T[] {
return docs.map(d => ContentItem.castAs(d, proto));
}
init() { }
}
@Adam111p의 투고에서는 (assign()을 사용한) 유사한 메커니즘이 언급되어 있습니다.또 하나의 방법일 뿐이다.@Timothy Perez는 할당에 대해 비판적이지만, 여기서는 충분히 적절하다.
파생(실제) 클래스를 구현합니다.
import { ContentItem } from './content-item';
export class SubjectArea extends ContentItem {
id: number;
title: string;
areas: SubjectArea[]; // contains embedded objects
depth: number;
// method will be unavailable unless we use cast
lead(): string {
return '. '.repeat(this.depth);
}
// in case we have embedded objects, call cast on them here
init() {
if (this.areas) {
this.areas = ContentItem.castAllAs(this.areas, SubjectArea);
}
}
}
이제 서비스에서 가져온 개체를 캐스팅할 수 있습니다.
const area = ContentItem.castAs<SubjectArea>(docFromREST, SubjectArea);
SubjectArea 객체의 모든 계층에는 올바른 클래스가 있습니다.
사용 사례/예: Angular 서비스를 만듭니다(기본 클래스를 다시 추상화).
export abstract class BaseService<T extends ContentItem> {
BASE_URL = 'http://host:port/';
protected abstract http: Http;
abstract path: string;
abstract subClass: typeof ContentItem;
cast(source: T): T {
return ContentItem.castAs(source, this.subClass);
}
castAll(source: T[]): T[] {
return ContentItem.castAllAs(source, this.subClass);
}
constructor() { }
get(): Promise<T[]> {
const value = this.http.get(`${this.BASE_URL}${this.path}`)
.toPromise()
.then(response => {
const items: T[] = this.castAll(response.json());
return items;
});
return value;
}
}
사용이 매우 간단해집니다. 영역 서비스를 만듭니다.
@Injectable()
export class SubjectAreaService extends BaseService<SubjectArea> {
path = 'area';
subClass = SubjectArea;
constructor(protected http: Http) { super(); }
}
서비스의 get() 메서드는 SubjectArea 개체로 이미 캐스트된 배열의 Promise를 반환합니다(전체 계층).
이제 다른 클래스가 있다고 가정해 보겠습니다.
export class OtherItem extends ContentItem {...}
데이터를 검색하고 올바른 클래스에 캐스트하는 서비스를 만드는 작업은 다음과 같이 간단합니다.
@Injectable()
export class OtherItemService extends BaseService<OtherItem> {
path = 'other';
subClass = OtherItem;
constructor(protected http: Http) { super(); }
}
만들 수 요.interface 타입의('유형')SomeType그 안에 오브젝트를 캐스팅합니다.
const typedObject: SomeType = <SomeType> responseObject;
JAVA 애호가용
POJO 클래스 만들기
export default class TransactionDTO{
constructor() {
}
}
클래스별로 빈 개체 만들기
let dto = new TransactionDto() // ts object
let json = {name:"Kamal",age:40} // js object
let transaction: TransactionDto = Object.assign(dto,JSON.parse(JSON.stringify(json)));//conversion
이 사이트를 사용하여 프록시를 생성할 수 있습니다.클래스를 생성하고 입력 JSON 개체를 해석 및 검증할 수 있습니다.
이 라이브러리는 여기서 사용하였습니다.https://github.com/pleerock/class-transformer
<script lang="ts">
import { plainToClass } from 'class-transformer';
</script>
구현:
private async getClassTypeValue() {
const value = await plainToClass(ProductNewsItem, JSON.parse(response.data));
}
경우에 따라서는 플레인 ToClass의 JSON 값을 해석하여 JSON 형식의 데이터임을 이해해야 합니다.
Lates TS에서는 다음과 같이 할 수 있습니다.
const isMyInterface = (val: any): val is MyInterface => {
if (!val) { return false; }
if (!val.myProp) { return false; }
return true;
};
그리고 다음과 같은 사용자:
if (isMyInterface(data)) {
// now data will be type of MyInterface
}
나도 비슷한 욕구가 생겼다.REST API 호출에서 특정 클래스 정의로 전송되는 JSON에서 쉽게 전환할 수 있는 것을 원했습니다.제가 찾은 솔루션은 제 수업의 코드를 다시 쓰고 주석이나 시뮬러를 추가하는 데 불충분하거나 의도된 것이 아니었습니다.
JSON 객체와의 클래스를 시리얼화/디시리얼라이즈하기 위해 Java에서 GSON과 같은 것을 사용하고 싶었습니다.
JS에서도 컨버터가 기능하기 때문에 나중에 필요하게 되어, 독자적인 패키지 작성을 종료했습니다.
하지만, 약간의 오버헤드가 있습니다.그러나 시작할 때 추가 및 편집이 매우 편리합니다.
모듈을 초기화하려면 다음 명령을 사용합니다.
- 변환 스키마 - 필드 간 매핑 및 변환 방법 결정
- 클래스 맵 배열
- 변환 함수 맵 - 특수 변환용.
다음으로 코드에서는 다음과 같은 초기화 모듈을 사용합니다.
const convertedNewClassesArray : MyClass[] = this.converter.convert<MyClass>(jsonObjArray, 'MyClass');
const convertedNewClass : MyClass = this.converter.convertOneObject<MyClass>(jsonObj, 'MyClass');
또는, JSON:
const jsonObject = this.converter.convertToJson(myClassInstance);
npm 패키지에 대한 링크 및 모듈 사용 방법에 대한 자세한 설명:json-class-converter
포장도 했습니다.
각도 사용 : angular-json-class-converter
개체를 그대로 클래스 생성자에게 전달합니다. 규칙 또는 검사 없음
interface iPerson {
name: string;
age: number;
}
class Person {
constructor(private person: iPerson) { }
toString(): string {
return this.person.name + ' is ' + this.person.age;
}
}
// runs this as //
const object1 = { name: 'Watson1', age: 64 };
const object2 = { name: 'Watson2' }; // age is missing
const person1 = new Person(object1);
const person2 = new Person(object2 as iPerson); // now matches constructor
console.log(person1.toString()) // Watson1 is 64
console.log(person2.toString()) // Watson2 is undefined
이 npm 패키지를 사용할 수 있습니다.https://www.npmjs.com/package/class-converter
다음과 같이 사용하기 쉽습니다.
class UserModel {
@property('i')
id: number;
@property('n')
name: string;
}
const userRaw = {
i: 1234,
n: 'name',
};
// use toClass to convert plain object to class
const userModel = toClass(userRaw, UserModel);
// you will get a class, just like below one
// const userModel = {
// id: 1234,
// name: 'name',
// }
tapi.js 하나로 할 수 있어요!두 가지 방식으로 작동하는 경량 오토마퍼입니다.
npm i -D tapi.js
그러면 간단하게 할 수 있습니다.
let typedObject = new YourClass().fromJSON(jsonData)
또는 약속과 함께
axios.get(...).as(YourClass).then(typedObject => { ... })
자세한 내용은 문서를 참조하십시오.
몇 가지 방법이 있습니다.몇 가지 옵션을 살펴보겠습니다.
class Person {
id: number | undefined;
firstName: string | undefined;
//? mark for note not required attribute.
lastName?: string;
}
// Option 1: Fill any attribute and it would be accepted.
const person1= { firstName: 'Cassio' } as Person ;
console.log(person1);
// Option 2. All attributes must assign data.
const person2: Person = { id: 1, firstName: 'Cassio', lastName:'Seffrin' };
console.log(person2);
// Option 3. Use partial interface if all attribute not required.
const person3: Partial<Person> = { firstName: 'Cassio' };
console.log(person3);
// Option 4. As lastName is optional it will work
const person4: Person = { id:2, firstName: 'Cassio' };
console.log(person4);
// Option 5. Fill any attribute and it would be accepted.
const person5 = <Person> {firstName: 'Cassio'};
console.log(person5 );
결과:
[LOG]: {
"firstName": "Cassio"
}
[LOG]: {
"id": 1,
"firstName": "Cassio",
"lastName": "Seffrin"
}
[LOG]: {
"firstName": "Cassio"
}
[LOG]: {
"id": 2,
"firstName": "Cassio"
}
[LOG]: {
"firstName": "Cassio"
}
Typescript 클래스가 아닌 인터페이스가 있는 경우에도 동작합니다.
interface PersonInterface {
id: number;
firstName: string;
lastName?: string;
}
저는 json2 typescript가 좋은 대안이라고 생각합니다.https://www.npmjs.com/package/json2typescript
주석이 있는 단순 모델 클래스를 사용하여 json을 클래스 모델로 변환할 수 있습니다.
프로젝트에서 사용
이것은 간단하고 매우 좋은 옵션입니다.
let person = "{"name":"Sam","Age":"30"}";
const jsonParse: ((key: string, value: any) => any) | undefined = undefined;
let objectConverted = JSON.parse(textValue, jsonParse);
그리고 넌...
objectConverted.name
이렇게 json을 부동산에 캐스팅할 수 있습니다.
class Jobs {
constructor(JSONdata) {
this.HEAT = JSONdata.HEAT;
this.HEAT_EAF = JSONdata.HEAT_EAF;
}
}
var job = new Jobs({HEAT:'123',HEAT_EAF:'456'});
언급URL : https://stackoverflow.com/questions/22875636/how-do-i-cast-a-json-object-to-a-typescript-class
'programing' 카테고리의 다른 글
| JSON jsonObject.optString()이 문자열 "null"을 반환합니다. (0) | 2023.03.16 |
|---|---|
| 리액트 라우터에서 수동으로 링크를 호출하는 방법 (0) | 2023.03.16 |
| PHP를 사용하여 WordPress에서 페이지 제목 설정 (0) | 2023.03.16 |
| AngularJs ng트리거 onblur 변경 (0) | 2023.03.16 |
| MongoDB에 있는 모든 문서의 필드 이름을 변경하려면 어떻게 해야 합니까? (0) | 2023.03.16 |