在typescript中将json解析为接口,并检查是否正确

sr4lhrrt  于 2023-10-21  发布在  TypeScript
关注(0)|答案(2)|浏览(242)

如何将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方法无效的例子:操场

ep6jt1vc

ep6jt1vc1#

如果您的验证需求足够复杂,我会评估io-ts之类的东西的使用。它是一个库,用于根据代码中的元数据自动生成运行时验证。
如果您的需求更有限,您可以只利用用户定义的类型保护。
类型保护所做的是接受一个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;
}
ar5n3qh5

ar5n3qh52#

它似乎工作,但它是非常复杂的维护代码,有没有其他方法更维护?
是的,你可以让typia生成函数。给定以下类型脚本输入:

import typia from "typia";

export interface User {
    name: Field;
    surname: Field;
};
export type Field = { icon: string; text: string; visibility: boolean };

const IsUser = typia.createIs<User>();

const u1 = {
    name: { icon: "i", text: "t", visibility: true },
    surname: { icon: "i", text: "t", visibility: true },
};

const u2 = {
    name: { text: "t", visibility: true },
    surname: { icon: "i", text: "t", visibility: true },
};

if (IsUser(u1)) {
    console.log("u1 is User");
} else {
    console.log("u1 is not User");
}

if (IsUser(u2)) {
    console.log("u2 is User");
} else {
    console.log("u2 is not User");
}

编译后的JavaScript是

import typia from "typia";
;
const IsUser = input => {
    return "object" === typeof input && null !== input && ("object" === typeof input.name && null !== input.name && ("string" === typeof input.name.icon && "string" === typeof input.name.text && "boolean" === typeof input.name.visibility) && ("object" === typeof input.surname && null !== input.surname && ("string" === typeof input.surname.icon && "string" === typeof input.surname.text && "boolean" === typeof input.surname.visibility)));
};
const u1 = {
    name: { icon: "i", text: "t", visibility: true },
    surname: { icon: "i", text: "t", visibility: true },
};
const u2 = {
    name: { text: "t", visibility: true },
    surname: { icon: "i", text: "t", visibility: true },
};
if (IsUser(u1)) {
    console.log("u1 is User");
}
else {
    console.log("u1 is not User");
}
if (IsUser(u2)) {
    console.log("u2 is User");
}
else {
    console.log("u2 is not User");
}

并且输出是

u1 is User
u2 is not User

所有的魔力都在IsUser函数中,你不必自己创建。

相关问题