如何将JSON对象转换为打字稿类

我从远程REST服务器读取JSON对象。 这个JSON对象具有打字稿类的所有属性(按devise)。 如何将接收到的JSON对象转换为typesvar?

我不想填充一个打字稿变种(即有一个构造函数,采取这个JSON对象)。 它很大,并通过子对象和财产属性复制子对象的一切将花费大量的时间。

更新:但是你可以把它转换成打字稿界面!

您不能简单地将来自Ajax请求的纯旧JavaScript结果转换为原型JavaScript / TypeScript类实例。 有很多技术可以做到这一点,通常涉及复制数据。 除非你创build了一个类的实例,否则它将没有任何方法或属性。 它将保持一个简单的JavaScript对象。

而如果你只是处理数据,你可以对接口进行转换(因为它纯粹是一个编译时结构),这就要求你使用一个TypeScript类,它使用数据实例并对这些数据执行操作。

一些复制数据的例子:

  1. 将AJAX JSON对象复制到现有对象中
  2. 将JSONstringparsing为JavaScript中的特定对象原型

本质上,你只是:

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

在TypeScript中,你可以使用如下的接口和generics来进行types断言 :

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

ILocationMap描述了你的数据的形状。 这种方法的优点是你的JSON可以包含更多的属性,但形状满足接口的条件。

我希望有帮助!

我发现了一个非常有趣的JSONtypes转换为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 

我有同样的问题,我find了一个工作的图书馆: https : //github.com/pleerock/class-transformer 。

它是这样工作的:

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

它支持嵌套的孩子,但你必须装饰你的class级的成员。

假设json具有与打字稿类相同的属性,则不必将Json属性复制到打字稿对象中。 你将只需要构造你的Typescript对象在构造函数中传递json数据。

在你的Ajaxcallback中,你收到一个公司:

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

为了做到这一点,

1)在您的Typescript类中添加一个将json数据作为参数的构造函数。 在该构造函数中,使用jQuery扩展json对象,如下所示: $.extend( this, jsonData) 。 $ .extend允许在添加json对象的属性的同时保持javascript原型。

2)注意你必须为链接的对象做同样的事情。 在示例中的员工情况下,您还可以创build一个构造函数,为员工提供部分json数据。 您可以调用$ .map将json雇员转换为打字稿员工对象。

 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对象时find的最佳解决scheme。

如果你使用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() }) 

但是,这种方式不会在巢的对象,悲伤。

在我的情况下,它的作品。 我使用了函数Object.assign(target,sources …) 。 首先,创build正确的对象,然后将数据从json对象复制到target。例如:

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

TLDR:一个class轮

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

详细的答案

推荐使用Object.assign方法,因为它可能不适当地抛弃了你的类实例,而是在类中没有声明的不相关的属性(以及定义的闭包)。

在你试图反序列化的类中,我将确保你想要反序列化的属性被定义(null,空数组等)。 通过使用初始值定义属性,当您尝试迭代类成员以将值分配给(请参阅下面的反序列化方法)时,公开其可见性。

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

在上面的例子中,我简单地创build了反序列化方法。 在现实世界的例子中,我将它集中在一个可重用的基类或服务方法中。

这里是如何利用这个东西像一个http resp …

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

如果tslint / ide抱怨参数types不兼容,只需使用尖括号<YourClassName>将参数转换为相同的types,例如:

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

如果你有一个特定types的类成员(又名:另一个类的实例),那么你可以通过getter / setter方法将它们转换成types实例。

 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和任务列表反序列化到它们各自的类实例中。

虽然不是说每个人都说; 我发现https://github.com/JohnWhiteTB/TypedJSON是一个有用的select。;

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

我创build了一个简单的工具来执行此操作https://beshanoe.github.io/json2ts/与json2ts.com不同,它直接在浏览器中运行,不会将数据发送到未知服务器。; 它也有多个设置。 我会努力改进它的function

我们做的一件事,因为我们是一个.NET商店是创build这个工具( https://github.com/Centeva/TypeScripter )。

它从我们的dll构build打字稿类。 我们所要做的就是将我们的反应json作为parameter passing给这个类。 它适合我们。