如何使用Typescript接口验证从输入接收到的JSON?

3

我有一个输入字段(文本区域),它接收以JSON格式表示的对象数组,我必须根据在TypeScript中创建的接口在运行时验证每个数组元素。

我创建了带有自定义类型roleType的接口EmployeeAddress

interface Employee {
  name: string;
  age: number;
  email: string;
  address?: Address;
  role?: roleType;
}

interface Address{
  city: string;
  pinCode: number;
}

type roleType = 'Developer' | 'UI Designer';

有效的JSON:

[
  {
    "name": "John Doe",
    "age": 25,
    "email": "john@email.com",
  },
  {
    "name": "Jane Doe",
    "age": 23,
    "email": "jane@email.com",
  }
]

无效的 JSON:

[
  {
    "name": "John Doe",
    "age": 25,
    "language": "typescript",
  },
  {
    "name": "Jane Doe",
    "age": 23,
    "email": "jane@email.com",
  }
]

然后尝试使用一个名为checkArray的函数,像这样:

function checkArray(array: any[]) {
  if (!Array.isArray(array)) {
    return false;
  }

  for (let i = 0; i < array.length; i++) {
    if (!(array[i] instanceof Employee)) {
      return false;
    }
  }

  return true;
}

但是这样做不起作用,因为接口Employee是一种类型,我们不能将其作为instanceof的值使用。

如何使用接口类型验证我的数组并生成适当的错误,而不使用任何外部库?

1个回答

2

在 TypeScript 中,您无法在运行时执行此操作,因为 TypeScript 会被转译成 JavaScript。 interface 是 TypeScript 的语法。

但是,您可以拥有一个属性名称和 JavaScript typeof 值的映射表。

interface Employee {
  name: string;
  age: number;
  email: string;
  manager: {
    name: string;
  }
  skills: string[];
}

type EmployeeValidationMap = Record<keyof Employee, string> & { [key: string]: string};

const jsMapForValidation: EmployeeValidationMap = {
  name: "string",
  age: "number",
  email: "string",
  manager: "object",
  skills: "array"
}


const validate = (employee: Employee) => {
return Object.entries(employee).map(([prop, value]) => {
  let passedValidation: boolean = false;
  if (jsMapForValidation[prop] === "array") {
    passedValidation = Array.isArray(value);
  } else {
    passedValidation = typeof value === jsMapForValidation[prop]
  }
  return { [prop]: passedValidation };
})
}


const validEmployee: Employee = {
  name: "Rob",
  age: 99,
  email: "rob@rob.com",
  manager: {
    name: "Boss"
  },
  skills: ["JavaScript", "TypeScript"]
}

const invalidEmployee: Employee = {
  name: "Rob",
  age: "not a number" as any,
  email: "rob@rob.com",
  manager: undefined as any,
  skills: 123 as any,
}

// 1. Validating valid employee object (returns true if data type is expected)
console.log(validate(validEmployee));
/*}, {
  "skills": true
}] 
[LOG]: [{
  "name": true
}, {
  "age": true
}, {
  "email": true
}, {
  "manager": true
}, {
  "skills": true
}] 
*/

// 2. Validating invalid employee object (returns false if data type is not expected, in this case age is a string and not a number)
console.log(validate(invalidEmployee));
/*
[LOG]: [{
  "name": true
}, {
  "age": false     <------ Age is a number not a string
}, {
  "email": true
}, {
  "manager": false    <------ Manager is not an object
}, {
  "skills": false   <------ Skills is not an array
}] 
*/
*/

这里是 TS playground


1
谢谢您分享您的答案。对于原始类型,它按预期工作,但对于非原始类型(如对象、联合类型和嵌套接口),它无法正常工作。您能否也分享一些相关信息?@Robert Rendell - Shevya
1
我已经添加了对对象的支持。由于在运行时它是 JavaScript,所以 TypeScript 无法在运行时验证联合类型和接口。 - Robert Rendell
1
我也添加了对数组的支持。祝你有美好的一天。 - Robert Rendell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接