mostrar leer externo estructura ejemplos ejemplo datos create crear con json typescript

externo - leer json javascript



¿Cómo puedo lanzar un objeto JSON a una clase de escritura de tipos (16)

Leí un objeto JSON desde un servidor REST remoto. Este objeto JSON tiene todas las propiedades de una clase de escritura de tipos (por diseño). ¿Cómo emito ese objeto JSON recibido a un tipo var?

No quiero rellenar una var tipográfica (es decir, tener un constructor que tome este objeto JSON). Es grande y copiar todo el subobjeto por subobjeto y propiedad por propiedad llevaría mucho tiempo.

Actualización: ¡Sin embargo, puedes convertirlo en una interfaz de escritura de tipos!


En TypeScript puedes hacer una aserción de tipo usando una interfaz y genéricos como:

var json = Utilities.JSONLoader.loadFromFile("../docs/location_map.json"); var locations: Array<ILocationMap> = JSON.parse(json).location;

Donde ILocationMap describe la forma de sus datos. La ventaja de este método es que su JSON podría contener más propiedades, pero la forma satisface las condiciones de la interfaz.

¡Espero que eso ayude!


En mi caso funciona. Utilicé funciones Object.assign (destino, fuentes ...) . Primero, la creación del objeto correcto, luego copia los datos del objeto json al objetivo. Ejemplo:

let u:User = new User(); Object.assign(u , jsonUsers);

Y un ejemplo más avanzado de uso. Un ejemplo utilizando la matriz.

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; } }


Encontré un artículo muy interesante sobre la conversión genérica de JSON a una clase de Typescript:

http://cloudmark.github.io/Json-Mapping/

Terminas con el siguiente código:

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


Esta es una opción simple y muy buena.

let person = "{"name":"Sam","Age":"30"}"; const jsonParse: ((key: string, value: any) => any) | undefined = undefined; let objectConverted = JSON.parse(textValue, jsonParse);

Y entonces tendrás

objectConverted.name


He creado una herramienta sencilla para hacer esto beshanoe.github.io/json2ts A diferencia de json2ts.com, funciona directamente en el navegador y no envía sus datos a servidores desconocidos. También tiene múltiples configuraciones. Trabajaré para mejorar su funcionalidad.


No se puede simplemente emitir un resultado simple de JavaScript de una solicitud Ajax en una instancia de clase prototípica JavaScript / TypeScript. Existen varias técnicas para hacerlo, y generalmente implican copiar datos. A menos que cree una instancia de la clase, no tendrá ningún método o propiedad. Seguirá siendo un simple objeto de JavaScript.

Si bien, si solo estuviera tratando con datos, podría hacer una conversión a una interfaz (ya que es simplemente una estructura de tiempo de compilación), esto requeriría que use una clase de TypeScript que use la instancia de datos y realice operaciones con esos datos.

Algunos ejemplos de copiar los datos:

  1. Copiando objeto AJAX JSON en un objeto existente
  2. Analizar la cadena JSON en un prototipo de objeto particular en JavaScript

En esencia, usted simplemente:

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



Si bien no es casting por decir; He encontrado https://github.com/JohnWhiteTB/TypedJSON como una alternativa útil.

@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"


Si está utilizando ES6, intente esto:

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() })

Pero de esta manera no funcionará en el objeto nido, lamentablemente.


Suponiendo que el json tiene las mismas propiedades que su clase de escritura, no tiene que copiar sus propiedades de Json a su objeto de escritura. Solo tendrá que construir su objeto Typescript pasando los datos json en el constructor.

En su devolución de llamada ajax, recibe una empresa:

onReceiveCompany( jsonCompany : any ) { let newCompany = new Company( jsonCompany ); // call the methods on your newCompany object ... }

Para poder hacer ese trabajo:

1) Agregue un constructor en su clase Typescript que tome los datos json como parámetro. En ese constructor extiendes tu objeto json con jQuery, así: $.extend( this, jsonData) . $ .extend permite mantener los prototipos de javascript mientras agrega las propiedades del objeto json.

2) Tenga en cuenta que tendrá que hacer lo mismo para los objetos vinculados. En el caso de Empleados en el ejemplo, también crea un constructor que toma la parte de los datos de json para los empleados. Llama a $ .map para traducir los empleados de json a los objetos de mecanografiado de los empleados.

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); } }

Esta es la mejor solución que encontré al tratar con las clases de Typescript y los objetos json.


Todavía no hay nada que verifique automáticamente si el objeto JSON que recibió del servidor tiene las propiedades de la interfaz de escritura de tipo esperadas (la lectura cumple con las). Pero puedes usar Guardias de Tipo Definido por el Usuario

Teniendo en cuenta la siguiente interfaz y un objeto json tonto (podría haber sido de cualquier tipo):

interface MyInterface { key: string; } const json: object = { "key": "value" }

Tres formas posibles:

A. Aserción de tipo o simple conversión estática colocada después de la variable

const myObject: MyInterface = json as MyInterface;

B. Reparto estático simple, antes de la variable y entre diamantes.

const myObject: MyInterface = <MyInterface>json;

C. Reparto dinámico avanzado, usted mismo verifica la estructura del objeto.

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}''.`); }

Puedes jugar con este ejemplo aquí.

Tenga en cuenta que la dificultad aquí es escribir la función isMyInterface . Espero que TS agregue un decorador tarde o temprano para exportar la escritura compleja al tiempo de ejecución y permita que el tiempo de ejecución compruebe la estructura del objeto cuando sea necesario. Por ahora, puede usar un validador de esquema json cuyo propósito es aproximadamente el mismo O este generador de funciones de verificación de tipo de tiempo de ejecución


Tuve el mismo problema y he encontrado una biblioteca que hace el trabajo: https://github.com/pleerock/class-transformer .

Funciona así :

let jsonObject = response.json() as Object; let fooInstance = plainToClass(Models.Foo, jsonObject); return fooInstance;

Es compatible con niños anidados, pero tienes que decorar a los miembros de tu clase.


Una cosa que hicimos porque somos una tienda .NET es crear esta herramienta ( https://github.com/Centeva/TypeScripter ).

Construye clases de escritura de tipos de nuestros dlls. Todo lo que tenemos que hacer es canalizar nuestra respuesta json a la clase como parámetro. Funciona bien para nosotros.


Una vieja pregunta con respuestas en su mayoría correctas, pero no muy eficientes. Esto es lo que propongo:

Cree una clase base que contenga el método init () y los métodos de conversión estática (para un solo objeto y una matriz). Los métodos estáticos podrían estar en cualquier lugar; la versión con la clase base y init () permite extensiones fáciles después.

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() { } }

Se han mencionado mecanismos similares (con assign () ) en la publicación @ Adam111p. Solo otra forma (más completa) de hacerlo. @Timothy Pérez critica a assign () , pero ahora es completamente apropiado aquí.

Implementar una clase derivada (la real):

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); } } }

Ahora podemos lanzar un objeto recuperado del servicio:

const area = ContentItem.castAs<SubjectArea>(docFromREST, SubjectArea);

Toda la jerarquía de objetos SubjectArea tendrá la clase correcta.

Un caso de uso / ejemplo; crear un servicio Angular (clase base abstracta de nuevo):

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; } }

El uso se vuelve muy simple; crear un servicio de área:

@Injectable() export class SubjectAreaService extends BaseService<SubjectArea> { path = ''area''; subClass = SubjectArea; constructor(protected http: Http) { super(); } }

El método get () del servicio devolverá una promesa de una matriz ya convertida en objetos SubjectArea (toda la jerarquía)

Ahora digamos, tenemos otra clase:

export class OtherItem extends ContentItem {...}

Crear un servicio que recupera datos y convierte a la clase correcta es tan simple como:

@Injectable() export class OtherItemService extends BaseService<OtherItem> { path = ''other''; subClass = OtherItem; constructor(protected http: Http) { super(); } }


Utilicé esta biblioteca aquí: https://github.com/pleerock/class-transformer

<script lang="ts"> import { plainToClass } from ''class-transformer''; </script>

Implementación:

private async getClassTypeValue() { const value = await plainToClass(ProductNewsItem, JSON.parse(response.data)); }

A veces tendrá que analizar los valores JSON para plainToClass para comprender que se trata de datos con formato JSON


TLDR: un trazador de líneas

// This assumes your constructor method will assign properties from the arg. .map((instanceData: MyClass) => new MyClass(instanceData));

La respuesta detallada

No recomendaría el enfoque Object.assign, ya que puede ensuciar inadecuadamente su instancia de clase con propiedades irrelevantes (así como con cierres definidos) que no se declararon dentro de la misma clase.

En la clase en la que está intentando deserializar, me aseguraría de que todas las propiedades que desea deserializar estén definidas (nula, matriz vacía, etc.). Al definir sus propiedades con valores iniciales, expone su visibilidad cuando intenta iterar a los miembros de la clase para asignar valores a (consulte el método de deserialización a continuación).

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]; } } } }

En el ejemplo anterior, simplemente creé un método de deserialización. En un ejemplo del mundo real, lo tendría centralizado en una clase base reutilizable o un método de servicio.

Aquí es cómo utilizar esto en algo así como una respuesta http ...

this.http.get(ENDPOINT_URL) .map(res => res.json()) .map((resp: Person) => new Person(resp) ) );

Si tslint / ide se queja de que el tipo de argumento es incompatible, simplemente convierta el argumento en el mismo tipo usando corchetes angulares <YourClassName> , ejemplo:

const person = new Person(<Person> { name: ''John'', age: 35, id: 1 });

Si tiene miembros de clase que son de un tipo específico (también conocido como: instancia de otra clase), puede convertirlos en instancias escritas a través de los métodos 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)); } }

El ejemplo anterior deserializará tanto la cuenta como la lista de tareas en sus instancias de clase respectivas.