简体   繁体   中英

How to check type of a JSON object against typescript interface in React

I have a result JSON object being passed onto a function which I would need to check the type of it against a Typescript interface definition model, in order to be perform specific rendering changes prior displaying it.

I am facing an issue, where the string matches all the interface types as it goes through the checks, using (jsonResult as TypeScriptInterfaceName) and simply doesnt deliver the correct value subsequently.

I tried the class transformer library as well with no luck. Whats the best way to explicitly check and fail the string against the typescript definition.

Thank you.

interface ParentOne {
    id: string;
    title: string;
    child: Child
}
interface Child {
    id: string;
    title: string;
}
**JSON ONE**
{
    id: value,
    title: value,
    child: [{}],
}


interface ParentTwo {
    id: string;
    title: string;
    directory: Directory
}
interface Directory {
    id: string;
    title: string;
}

**JSON TWO**
{
    id: value,
    title: value,
    directory: [{}],
}

When you're parsing JSON the resulting type will be any . Type information doesn't exist at runtime, so Typescript can't help you there.

What we do is create a JSON-Schema file that describes the JSON file, and then we use a JSON-Schema validator like ajv to validate if the incoming JSON object matches the schema.

We then use a tool like json-schema-to-typescript to generate types based on the schemas.

Our validation function finally looks something like this:

function validateBody<T>(body: unknown, jsonSchemaId: string): asserts body is T {

   // Do validation or throw error

}

This means that from a single JSON-Schema, we get:

  1. Typescript types in the backend
  2. Typescript types in the frontend
  3. Documentation
  4. A server-side validator with useful errors.
  5. Type-safety (after validation)

Because you don't have the interface definitions at runtime you can't count on them for sanity checking, what you might do is something like the following.

Given some useful interfaces

interface ParentOne {
    id: string;
    title: string;
    child: Child
}
interface Child {
    id: string;
    title: string;
}

interface ParentTwo {
    id: string;
    title: string;
    directory: Directory
}
interface Directory {
    id: string;
    title: string;
}

We want a way to use those nice interfaces

const processParentOne = (p: ParentOne) => {
  console.log(p.child);
}

const processParentTwo = (p: ParentTwo) => {
  console.log(p.directory);
}

So we cast them as soon as we can infer the type

const processionJson = (data: any) => {
  if (!!data.child) {
    processParentOne(data as ParentOne);
  } else if(!!data.directory) {
    processParentTwo(data as ParentTwo);
  }
}

So that we can do something like

const p1: ParentOne = {
  id: 'po',
  title: "p1",
  child: {
    id: 'chopo',
    title: 'little'
  }
}

const p2: ParentTwo = {
  id: 'pt',
  title: 'p2',
  directory: {
    id: 'dirpt',
    title: 'dict'
  }
}

// Remove all the type info for example
const json = (Math.random() < .5) 
  ? JSON.stringify(p1) : JSON.stringify(p2);

// pass along "unknown" data type
processionJson(JSON.parse(json))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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