将 json 解析为 typescript 中的接口并检查是不是正常

Posted

技术标签:

【中文标题】将 json 解析为 typescript 中的接口并检查是不是正常【英文标题】:Parsing json to interface in typescript and check if it is ok将 json 解析为 typescript 中的接口并检查是否正常 【发布时间】:2020-12-17 02:53:33 【问题描述】:

如何将 Json 字符串解析为嵌套接口类型?并检查是否正常?

我有一个例子,但我的模型更复杂:

export interface User = 
    name: Field;
    surname: Field;
;
export interface Field =  icon: string; text: string; visibility: boolean ;
export interface Users = User[]

应该是:

export type user = 
    name: field;
    surname: field;
;
export type field =  icon: string; text: string; visibility: boolean ;
export type users = user[]

或者它会是类。没关系。

这里是一个 json 示例:

[

"name":  "text": "David", "icon": "icon1.png", "visibility": true ,
"surname":  "text": "Smith", "icon": "icon2.png", "visibility": true 
,

"name":  "text": "Arthur", "icon": "icon3.png", "visibility": true ,
"surname":  "text": "L.", "icon": "icon6.png", "visibility": true 
,

"name":  "text": "Anthony", "icon": "icon1.png", "visibility": false ,
"surname":  "text": "Isaacson", "icon": "icon2.png", "visibility": true 
,

"name":  "text": "Mike", "icon": "icon3.png", "visibility": true ,
"surname":  "text": "Jobs", "icon": "icon5.png", "visibility": false 

]

编辑:

这里是 Chithambara 方法无效的示例:Playground

【问题讨论】:

【参考方案1】:

如果您的验证需求足够复杂,我会评估io-ts 之类的使用情况。它是一个用于根据代码中的元数据自动生成运行时验证的库。

如果您的需求比较有限,您可以利用UserDefined Type Guards。

类型保护的作用是获取unknown(或any,这种函数内部确实没有区别)并告诉编译器传入的对象兼容某个界面。

export interface Field 
  icon: string;
  text: string;
  visibility: boolean;


export interface User 
  name: Field;
  surname: Field;


function isField(obj: any): obj is Field 
  return (
    obj != null &&
    typeof obj.icon === "string" &&
    typeof obj.text === "string" &&
    typeof obj.visibility === "boolean"
  );


function isUser(obj: any): obj is User 
  return obj != null && isField(obj.name) && isField(obj.surname);

  // you can get fancy and write something like
  // return obj != null && ['name', 'surname'].every(fieldName => isField(obj[fieldName]))


// alternative isUser implementation, using a 
// prototype. This will give you a compile error is the
// interface is updated, but not this prototype.
const userProto: User = 
  name: null,
  surname: null
;

function isUserDynamic(obj: any): obj is User 
  return obj != null && Object.keys(userProto).every(fieldName => isField(obj[fieldName]));


function validateUserArray(obj: any): obj is User[] 
  if (obj == null) 
    // depending upon the desired approach, you can throw an exception and bail out,
    // or simply return false.
    throw new Error("The array cannot be null");
  
  if (!Array.isArray(obj)) return false;

  obj.forEach((user, i) => 
    if (!isUser(user))
      throw new Error(
        `Error at index $i: $JSON.stringify(user) is not a valid user.`
      );
  );

  return true;


const json = `[
  
    "name":  "text": "David", "icon": "icon1.png", "visibility": true ,
    "surname":  "text": "Smith", "icon": "icon2.png", "visibility": true 
  ,
  
    "name":  "text": "Arthur", "icon": "icon3.png", "visibility": true ,
    "surname":  "text": "L.", "icon": "icon6.png", "visibility": true 
  ,
  
    "name":  "text": "Anthony", "icon": "icon1.png", "visibility": false ,
    "surname":  "text": "Isaacson", "icon": "icon2.png", "visibility": true 
  ,
  
    "name":  "text": "Mike", "icon": "icon3.png", "visibility": true ,
    "surname":  "text": "Jobs", "icon": "icon5.png", "visibility": false 
  
]`;

const deserialized: any = JSON.parse(json);

let validatedArray: User[];

if (validateUserArray(deserialized)) 
  // here deserialized is a User[], not an any.
  validatedArray = deserialized;

【讨论】:

看起来可以,但是代码维护起来很复杂,有没有其他更易维护的方法? 如果您的类型是“常规的”(即用户界面有 20 个字段,所有字段类型均为 Field),您可以将 User 设为类,使用 const proto = new User() 实例化原型并使用 Object。 keys(proto) 通过 isUser 中的return obj != null && Object.keys(proto).every(fieldName => isField(obj[fieldName])) 获取要检查的字段列表。 或者,使用io-ts。当然,更易于维护,但可能不是那么简单。您还可以构建一个代码生成器,为您构建isUser 函数,并在每次用户界面更改时运行它。 我添加了一个isUserDynamic 函数来替代isUser 来展示它是如何完成的,同时保持User 作为一个接口。

以上是关于将 json 解析为 typescript 中的接口并检查是不是正常的主要内容,如果未能解决你的问题,请参考以下文章

在 Typescript 中解析 JSON 对象

在 Angular 应用程序中将 JSON 解析为 Typescript 类

如何将打字稿定义解析为json?

如何在 Typescript 中保持代码 DRY 的同时解析多个 Json 文件?

Angular 2 - 将 JSON 解析为具有计算属性的类

从 Typescript 解析 JSON 恢复数据成员但不恢复类型:无法在结果上调用方法