简体   繁体   English

使用TypeScript和Angular2验证传入数据的类型

[英]validate types of incoming data with TypeScript and Angular2

I would like to know the recommended way to validate the data received from the server via AJAX or in child component via @input decorator in Angular2+ apps. 我想知道推荐的方法来验证通过AJAX或通过Angular2 +应用程序中的@input装饰器从子组件中从服务器接收的数据。 In the app I currently work with I use interfaces for this, but they do not validate incoming data, ie when some property is missing, no run time errors about invalid type are issued: 在当前使用的应用程序中,我为此使用接口,但是它们不验证传入的数据,即,当缺少某些属性时,不会发出有关无效类型的运行时错误:

// types.ts
export interface IAuthItem {
name: string;
type: number;
description: string;
rule_name: string | any;
data?: any;
created_at: number;
updated_at: number;
selected?: boolean;
}

export interface IAuthItemFormModel {
AuthItem: IAuthItem;
oldAuthItem: IAuthItem;
permissions: IAuthItem[];
assignments: IAuthItem[];
}

// component.ts

//other imports
import { IAuthItemFormModel,  IAuthItem  } from './types.ts';

....

@Input() model: IAuthItemFormModel;

  ngOnInit() {
  this.getData();
}

getData() {
  this.http.post('/api/admin/auth-item/form-data', 
    this.model).subscribe((data: IAuthItemFormModel) => {
  this.model = Object.assign(this.model, data);
  console.log(this.model);
  });
}

Interfaces does not exist on JS and you should think that TS is a superset for JS, but it gets transpiled into JS which is what the browser understands. 接口在JS上不存在,您应该认为TS是JS的超集,但是它被转换为JS,这是浏览器可以理解的。

The interface is just for you to offer some Intellisense and compile time errors for development. 该接口只为您提供一些Intellisense和编译时错误以进行开发。

Having said that, the only way you would have to validate that object by JS is looking into the params. 话虽如此,您必须通过JS验证该对象的唯一方法是研究参数。 You have few ways, one of them is by getOwnPropertyNames 您有几种方法,其中一种是通过getOwnPropertyNames

https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/getOwnPropertyNames https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/getOwnPropertyNames

DISCLAIMER: this is purely an example of a possible approach, this doesn't mean that it needs to be valid or whatever, this is just the approach I've been using lately and allows elasticity, which is what I was looking for. 免责声明:这纯粹是一种可行方法的示例,这并不意味着它必须有效,或者这是我最近一直在使用的允许弹性的方法,这正是我一直在寻找的方法。

Now, onto the point. 现在,到了重点。

Since interfaces don't exists in runtime, if you want to parse and effectively add any sort of "test" to acquire the desired data and eventually transform the data acquired, you should be using classes. 由于接口在运行时中不存在,因此,如果要解析并有效地添加任何种类的“测试”以获取所需的数据并最终转换所获取的数据,则应使用类。

Here is a little example, simulating this response: 这是一个模拟此响应的小示例:

const json_response = {
    status: "done",
    refere: {
        "id": 13,
        "name": "John"
    }
};

In our case, the logic I'm going to apply is having a Response Handler that takes care of the whole response, and a Referee class that handles the refere reference aswell. 在我们的例子中,我要应用的逻辑是拥有一个负责处理整个响应的Response Handler和一个Referee类,该类也处理Refere引用。

Starting from the Referee: 从裁判开始:

interface IReferee {
    id: number,
    name:   string
}

class Referee implements IReferee {
    public id: number;
    public name: string;

    private rawData: any;

    constructor(data?: any) {
        if (data !== null) {
            // Do some check here to check whether data is effectively coherent.
            this.id = +data.id;
            this.name = data.name;
        }
    }

    // This is the advantage of using a class.
    // Adding optional methods that may be useful here and there.
    get ID(): number {
        return this.id;
    }

    get LowerCaseName(): string {
        return this.name.toLowerCase();
    }

    get Name(): string {
        return this.name;
    }

    get UpperCaseName(): string {
        return this.name.toUpperCase();
    }
}

The interface is NOT mandatory, it's just useful to be sure that you implement everything correctly in the class itself. 该接口不是强制性的,它对于确保您在类本身中正确实现所有功能很有用。 The advantage here is that you can implement your own method if you want to (as seen above). 这样做的好处是,您可以根据需要实现自己的方法(如上所示)。

The response handler: 响应处理程序:

interface IMyJsonResponseHandler {
    status: string,
    refere: Referee 
}

class MyJsonResponseHandler implements IMyJsonResponseHandler {
    private rawData: any;

    public status: string;
    public refere: Referee;

    constructor(data?: any) {
        if (data !== null) {
            this.status = data.status;
            this.refere = new Referee(data.refere);
        }
    }

    get Refere(): Referee {
        return this.refere;
    }
}

And the same criteria is applied: basically, the param provided here is the json response. 并应用相同的条件:基本上,此处提供的参数是json响应。 Every single handling is done in the constructor, if you want to add any strict check, do it there and eventually throw errors or whatever you need there. 每一个处理都是在构造函数中完成的,如果您想添加任何严格的检查,请在此处进行检查,并最终抛出错误或在那里进行任何操作。 In this way, you can access pretty much everything of your json response and you can enjoy the intellisense thanks to interfaces and classes together. 这样,您几乎可以访问json响应的所有内容,而且由于接口和类在一起,您可以享受智能感知。 Of course you can simply accept that the JSON response is typeless, but if you need to do some strict checks and need such data for other calculations or simply want to have an easier understanding of what the properties are, then you must use classes and do checks there, because interfaces in typescript are nothing but a comfort for the developer in this case. 当然,您可以简单地接受JSON响应是无类型的,但是如果您需要进行一些严格的检查并且需要此类数据进行其他计算,或者只是想更轻松地了解属性是什么,则必须使用类并执行检查那里,因为在这种情况下,打字稿中的接口不过是开发人员的一种便利。

Example usage: 用法示例:

const json_response = {
    status: "done",
    refere: {
        "id": 13,
        "name": "John"
    }
};
let res = new MyJsonResponseHandler(json_response);

console.log(res.Refere.LowerCaseName);

Playground with this example which logs: john . 带有以下示例的游乐场john

Advantage of this criteria: intellisense. 此标准的优势:智能感知。

Alternatively, you can just easily implement an interface, but if you need complex data elaboration (or, more easily, if you need an inner property to be instantialized as a class instance) you must use other criteria. 另外,您可以轻松地实现一个接口,但是如果您需要复杂的数据处理(或者更轻松地,如果您需要将内部属性实例化为类实例),则必须使用其他条件。

Other sources you should check: 您应检查的其他来源:

How to parse JSON string in Typescript 如何解析Typescript中的JSON字符串

How do I cast a JSON object to a typescript class 如何将JSON对象转换为Typescript类

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM