使用带有递归 JSON 的 Typescript 接口

Posted

技术标签:

【中文标题】使用带有递归 JSON 的 Typescript 接口【英文标题】:Using Typescript Interface with a Recursive JSON 【发布时间】:2018-06-25 11:12:40 【问题描述】:

我正在尝试使用 JSON 来调整产品的本体及其属性。下面提到的JSON结构是我正在考虑的。

每个产品(概念)都有两种类型的属性: 1. 数据属性 2. 对象属性

使用 Protege 时这些属性的典型定义如下SO Thread

在 Protégé 中有不同的选项卡用于创建对象属性和数据类型属性。如果一个属性应该将个人与个人联系起来,那么它需要是一个对象属性,如果它将个人与文字联系起来,那么它需要是一个数据类型属性。

我认为每个属性都具有以下属性:

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

我已经制定了一个小的递归 JSON 如下:


  "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"
        
        ]
    
  ]

在某种程度上,结构为椅子提供了一个二叉树,其中heightwidth 等作为数据属性horizontalsurfacelegislation 作为对象属性

JSON 到 Typescript 中的接口

我使用JSON to TS Online Converter 来查看如何将 JSON 转换为 Typescript 接口,结果如下:

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;

推理

我推断使用递归 JSON 中的接口的方法是不可扩展的,因为这样的产品本体可以扩展到 1000 个属性和属性中的属性。如上例所示,对于父属性中的每个属性,都会不断创建接口。

期待

我应该期望使用具有这种 JSON 结构的 Typescript 接口,还是应该坚持创建一个类,然后遵循创建二叉树的常规方法即。

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

然后写一个递归直到解析完整的结构?

TL;DR

Typescript 接口可以用于大型递归 JSON 结构吗?

【问题讨论】:

【参考方案1】:

您应该能够将该结构很好地表示为递归接口:

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

您尝试使用的 JSON 到 TS 转换器似乎没有识别结构递归性质的功能。

工作示例:

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"
        
        ]
    
  ]
`;

【讨论】:

@Kalle 您对我的回答所做的编辑很好,但它们不是我的工作。我建议您使用建议的方法添加自己的答案。 除了objPropSourceproperties 之外的好答案应该是接口的可选成员。【参考方案2】:

两个可能的帮手,让您在未来更轻松。

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]

判别器类型:

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',        
    

【讨论】:

以上是关于使用带有递归 JSON 的 Typescript 接口的主要内容,如果未能解决你的问题,请参考以下文章

带有接口的Typescript中的Json枚举?

在带有 JSON 的 Vue 组件中使用递归

带有 TypeScript 解析器/插件的 ESLint:如何包含从 tsconfig.json 中排除的 .spec.ts?

Typescript - 从带有日期字符串的 Json 字符串自动转换为带有 Date 属性的对象

带有 ESLint 的 TypeScript:解析错误:关键字“枚举”是保留的 eslint

如何使用对象解构在 TypeScript 中导入 JSON?