繁体   English   中英

Typescript ,声明具有不同类型的嵌套对象的最佳方法是什么?

[英]Typescript , what's the best approach for declaring a nested object with different types?

我有这个 JS 对象,我想将它移植到 Typescript:

var items = [{
      style: 'activity-8',
      color: '#a32c62',
      id:    8,
      done : false,
      label : {
        short :'999 m',
        long  :'walk 999m',
        statstime  :'yesterday'
      },
      val : {
        today : {
          target   : { 
            raw : 0,
            display :"11"
          },
          achieved : {
            raw : 0,
            display :"22"
          }
        },
        yesterday : {
          target   : {
            raw : 0,
            display :"33"
          },
          achieved : {
            raw : 0,
            display :"44"
          }
        }
      }
    },{
      style: 'activity-7',
      color: '#ec575d',
      id:    7,
      done : true,
      label : {
        short :'walk 555m',
        long  :'walk 555m',
        statstime  :'yesterday'
      },
      val : {
        today : {
          target   : { 
            raw : 0,
            display :"0"
          },
          achieved : {
            raw : 0,
            display :"0"
          }
        },
        yesterday : {
          target   : {
            raw : 0,
            display :"0"
          },
          achieved : {
            raw : 0,
            display :"0"
          }
        }
      }
    }];

声明此对象类型的最佳方法是什么? 我应该写下每个字段的类型吗? 还是创建自定义类型? 还有其他建议吗?

我不知道这是否是“最佳”方式,但我会举个例子来说明我的做法。

我将尝试解释我的一般规则,不仅适用于嵌套对象:

对于所有基本类型(字符串、数字、布尔值或某些数组)的属性,您可以将它们保留为这样,但对于从现在开始我将称为“复杂属性”的所有其他复杂属性/嵌套对象(因为它对我来说更有意义)你制作了一个接口,它将成为属性的类型。

示例:在您的情况下, val属性是一个“复杂”属性,因此让我们从下到上拆分它。

val 属性中最小的复杂属性是target ,因此您创建一个名为 Target 的接口(或 ITarget 在 ts 中并不完全是这样做的约定)Target 将类似于:

interface Target {
  raw: number,
  display: string
}

您对achieved “复杂”属性执行相同的操作。

现在您可以上一级。 Today属性也是一个“复杂”的属性,所以它必须有一种类型,可能是某种类型的接口。 由于我们之前的工作,界面看起来像:

interface Day {
  target: Target,
  achieved: Achieved
}

您可能想知道为什么接口被称为 Day 而不是 Today,原因是您必须找出yesterday “复杂”属性的类型。 如您所见,您可以看到它与today属性的类型相同,因为它内部具有相同的属性。

因此,最终作为我们目标的val属性将拥有自己的接口,类似于:

interface Val {
  today: Day,
  yesterday: Day
}

接下来,您对所有其他“复杂”属性执行相同的操作。

现在你可以在你的主对象中使用它们,它可能是一个类,它的属性类型将是那些接口。

不要忘记 ts 中的界面(不仅是)只是一个“帮助”工具,它仅有助于组织您的代码设计。 大多数时候,每个接口都应该有一个实现该接口的类。 这些是您将用于为这些属性实际设置某些值的类。

更新(4年后):

现在,当我对打字稿有更多经验时,我仍然会使用相同的策略,但我会使用type而不是interface来完成几乎相同的工作。 接口(对我来说)应该只在你打算有一个实现它们的类时使用。

如果你不想提取子类型(嵌套字段作为单独的类),因为它们只在那个地方使用,那么定义类如下(来自 head 的代码)

 export class MyItem { style: string; color: string; id: number; done: boolean; label: { short: string, long: string, statstime: string }; // ... and so on constructor(item: any) { if(item) Object.assign(this, item); // copy item fields to "this" fields } }; // and map your not-typed items table (eg readed from API) to typed let typedItem: MyItem[] = items.map(item => new MyItem(item));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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