Using Typescript Interface with a Recursive JSON
Asked Answered
C

2

5

I am trying to adapt a product's ontology with its properties using JSON. The below mentioned JSON structure is what I am thinking about.

Each Product (Concept) has two types of properties: 1. Data Properties 2. Object Properties

Typical Definitions for these properties when using Protege is as followsSO Thread:

In Protégé there are are different tabs for creating Object Properties and Datatype Properties. If a property should relate individuals to individuals, then it needs to be an object property, and if it relates individuals to literals, then it needs to be a datatype property.

I think of every property to have the following attributes:

name: string
url: string
type: dataprop or objprop
objPropSource: available only for Objproperties

I have drawn up a small recursive JSON as below:

{
  "name": "chair",
  "url": "http://namespace.org#chair",
  "type": "main",
  "properties": [
    {
      "name": "height",
      "url": "http://namespace.org#height",
      "type": "dataprop"
    },
    {
      "name": "width",
      "url": "http://namespace.org#width",
      "type": "dataprop"
    },
    {
      "name": "horizontalsurface",
      "url": "http://namespace.org#horizontalsurface",
      "type": "objprop",
      "objPropSource": "http://namespace.org#hasHorizontalSurface",
      "properties": [
        {
          "name": "Legislation",
          "url": "http://namespace.org#legislation",
          "type": "objprop",
          "objPropSource": "http://namespace.org#compliesWithLegislation",
          "properties": [
            {
              "name": "hasLegislationName",
              "url": "http://namespace.org#hasLegislationName",
              "type": "dataprop"
            }
            ]
        }
        ]
    },
    {
      "name": "legislation",
      "url": "http://namespace.org#legislation",
      "type": "objprop",
      "objPropSource": "http://namespace.org#compliesWithLegistion",
      "properties": [
        {
          "name": "hasLegislationName",
          "url": "http://namespace.org#hasLegislationName",
          "type": "dataprop"
        }
        ]
    }
  ]
}

In a way structure provides a Binary Tree for a chair which has height, width etc. as dataproperties and horizontalsurface and legislation as objectproperties

JSON to Interface in Typescript

I used the JSON to TS Online Converter to see how will the JSON be converted to Typescript Interfaces and the outcome is following:

interface RootObject {
  name: string;
  url: string;
  type: string;
  properties: Property3[];
}

interface Property3 {
  name: string;
  url: string;
  type: string;
  objPropSource?: string;
  properties?: Property2[];
}

interface Property2 {
  name: string;
  url: string;
  type: string;
  objPropSource?: string;
  properties?: Property[];
}

interface Property {
  name: string;
  url: string;
  type: string;
}

Inference

I infer that the aprroach for using Interfaces from Recursive JSON is not scalable since such an Ontology of a Product can scale upto 1000's of properties and properties within properties. As above mentioned example show that for every Property within a parent property would keep creating interfaces.

Expectation

Should I expect to use Typescript Interfaces with such JSON structure or should to stick to creating a Class and then following the conventional method of creating a Binary Tree viz.

export class leaf {
  name: string;
  url: string;
  type: string;
  children: leaf[] = [];
}

and then writing a recursion till the complete structure is parsed?

TL;DR

Can Typescript interfaces be used for Large Recursive JSON Structures?

Canticle answered 16/1, 2018 at 17:7 Comment(1)
If you frequently deal with complex, recursive JSON structures and value automation: json-5.com/json-to-typescript might be a good fit.Ripieno
S
17

You should be able to represent that structure just fine as a recursive interface:

interface Property {
  name: string;
  url: string;
  type: string;
  objPropSource?: string;
  properties?: Property[];
}

It appears that the JSON to TS converter you tried to use just doesn't have the functionality to recognize the recursive nature of your structure.

Working example:

interface Property {
  name: string;
  url: string;
  type: string;
  objPropSource?: string; // optional property
  properties?: Property[];
};

var p: Property = JSON.parse(getJson());

alert(p.properties[2].properties[0].name);
alert(p.properties[3].objPropSource);




function getJson() {
  return `{
  "name": "chair",
  "url": "http://namespace.org#chair",
  "type": "main",
  "properties": [
    {
      "name": "height",
      "url": "http://namespace.org#height",
      "type": "dataprop"
    },
    {
      "name": "width",
      "url": "http://namespace.org#width",
      "type": "dataprop"
    },
    {
      "name": "horizontalsurface",
      "url": "http://namespace.org#horizontalsurface",
      "type": "objprop",
      "objPropSource": "http://namespace.org#hasHorizontalSurface",
      "properties": [
        {
          "name": "Legislation",
          "url": "http://namespace.org#legislation",
          "type": "objprop",
          "objPropSource": "http://namespace.org#compliesWithLegislation",
          "properties": [
            {
              "name": "hasLegislationName",
              "url": "http://namespace.org#hasLegislationName",
              "type": "dataprop"
            }
            ]
        }
        ]
    },
    {
      "name": "legislation",
      "url": "http://namespace.org#legislation",
      "type": "objprop",
      "objPropSource": "http://namespace.org#compliesWithLegistion",
      "properties": [
        {
          "name": "hasLegislationName",
          "url": "http://namespace.org#hasLegislationName",
          "type": "dataprop"
        }
        ]
    }
  ]
}`;
}
Stopcock answered 16/1, 2018 at 17:16 Comment(2)
@Kalle The edits you made to my answer were nice, but they're not my work. I would suggest that you add your own answer with your suggested approach.Stopcock
Good answer except objPropSource and properties should be optional members of the interface.Odious
H
1

Two possible helpers for you, to make it easier in future.

type MakeRecusive<Keys extends string, T> = {
    [K in Keys]: T & MakeRecusive<K, T>
} & T


type MakeRecusiveObectKeys<TKeys extends string, T> = {
    [K in keyof T]: K extends TKeys ? T[K] & MakeRecusive<K, T[K]>: T[K]
}

Disciminator Types:

type BaseTypes = 'dataprop' | 'objprop'

interface BaseType<TType extends BaseTypes = 'dataprop'> {
    name: string;
    url: string;
    type: TType; 
    properties?: DiscriminatorType   
}

interface ObjProp extends BaseType<'objprop'>{

    objPropSource: string;
}

type DiscriminatorType = BaseType | ObjProp

const root: DiscriminatorType = {
    name:'name',
    type: 'dataprop',
    url:'string',
    properties: {
        name:'name2',
        type:'objprop',
        objPropSource:'sdf',
        url:'str',        
    }
}
Hazelton answered 24/8, 2021 at 9:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.