Typescript是声明不同类型嵌套对象的最佳方法

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

本文关键字:对象 最佳 方法 嵌套 同类型 声明 Typescript      更新时间:2023-09-26

我有这个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的接口(或者ittarget,在ts中这样做并不完全是惯例)Target将是这样的:

interface Target {
  raw: number,
  display: string
}

achieved的"complex"属性做同样的事情。

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

interface Day {
  target: Target,
  achieved: Achieved
}

你可能想知道为什么这个接口被称为Day而不是Today,原因是你必须找出yesterday"complex"属性的类型。正如你所看到的,它和today属性的类型是一样的因为它的内部属性是一样的

最后,我们的目标是val属性将有它自己的接口,类似于:

interface Val {
  today: Day,
  yesterday: Day
}

接下来,对其他"复杂"属性执行同样的操作。

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

不要忘记ts中的接口(不仅)只是一个"帮助"工具,它只是帮助组织你的代码设计。大多数情况下,每个接口都必须有一个实现该接口的类。这些是你会用来为那些属性设置值的类

更新(4年后):

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

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

interface MyItem {
  style: string,
    color: string,
    id: number,
    done: boolean,
    label: {
      short: string,
      long: string,
      statstime: string,
    },
    val: {
      today: {
        target: {
          raw: number,
          display: string
        },
        achieved: {
          raw: number,
          display: string,
        }
      },
      yesterday: {
        target: {
          raw: number,
          display: string,
        },
        achieved: {
          raw: number,
          display: string,
        }
      }
    }
};

// and map your not-typed items table (eg readed from API) to typed
let typedItem: MyItem[] = items.map(item => new MyItem(item));

用法如下

let items: MyItem[] = [{
  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"
      }
    }
  }
}];

下面是工作示例