繁体   English   中英

理解打字稿接口

[英]Understanding typescript interfaces

我想了解 typescript/javascript 的格式,并且需要帮助来理解此处的某些步骤。 我正在将 JSON 文件解析为一个对象,然后尝试读取值以更新某些值。

感谢 Timmy chan,我从我之前的帖子中得到了一些建议,现在以此为基础。 使用打字稿中 JSON 类型的接口创建对象

假设我定义了这个接口,

interface AllData {
  [value:string]:Row 
}

interface Row {
  eDate: string;
  mystate: string;
  mystateCity: string;
  numberofpeople: number;
}

let Data: AllData ;

我像这样读取文件并将其分配给 Data 变量。

 const response = await fetchFile(fileName);
    Data= await response.json();

现在我想创建一个只有行的新对象

 const CountData: Row[] = {} // this gives error Type '{}' is missing the following properties from type 'CountyGraphRow[]': length, pop, push,
 
if I change it to 
const CountData: Row[] = []  // when to have {} or [].. What is the difference?

  for (const rowData in Data["value"]) 
  {
    console.log(rowData); //  this is coming out 0
    CountData.push({  //  error at TypeError: Cannot read property 'eDate' of undefined
      eDate: Data[rowData].eDate,  // Something is wrong in the way I am accessing them.
      mystate: Data[rowData].mystate,
      mystateCity: Data[rowData].mystateCity,
      numberofpeople: Data[rowData].numberofpeople > 20? 20 : Data[rowData].numberofpeople < 5? 5: Data[rowData].numberofpeople,
    })
  }

这是文件的样子

{
  "value": [
    {
      "eDate": "2020-03-01T00:00:00.000Z",
      "mystate": "state1",
      "mystateCity": "state1, ID",
      "numberofpeople": 2.973529602
    },
    {
      "eDate": "2020-03-02T00:00:00.000Z",
      "mystate": "state1",
      "mystateCity": "state1, ID",
      "numberofpeople": 2.973529602
    },
    {
      "eDate": "2020-03-03T00:00:00.000Z",
      "mystate": "state1",
      "mystateCity": "state1, ID",
      "numberofpeople": 2.973529602
    }
]}

--------------更新2------------

interface AllData {
    [value: string]: Row
}

interface Row {
    eDate: string;
    mystate: string;
    mystateCity: string;
    numberofpeople: number;
}

let Data: AllData;

Data = JSON.parse(`{ 
  "value": [
    {
      "eDate": "2020-03-01T00:00:00.000Z",
      "mystate": "state1",
      "mystateCity": "state1, ID",
      "numberofpeople": 2.973529602
    },
    {
      "eDate": "2020-03-02T00:00:00.000Z",
      "mystate": "state1",
      "mystateCity": "state1, ID",
      "numberofpeople": 2.973529602
    },
    {
      "eDate": "2020-03-03T00:00:00.000Z",
      "mystate": "state1",
      "mystateCity": "state1, ID",
      "numberofpeople": 2.973529602
    }
]}`);

const CountData: Row[] = [];

for (const rowData in Data["value"]) { // Data["value"] I am assuming this //will pick all objects   "value": [
   // {
     // "eDate": "2020-03-01T00:00:00.000Z",
// please correct me if I am wrong

   

 console.log(rowData); //  this is coming out 0
    CountData.push({  //  error at TypeError: Cannot read property 'eDate' of undefined
        eDate: Data[rowData].eDate,  // Something is wrong in the way I am accessing them.
        mystate: Data[rowData].mystate,
        mystateCity: Data[rowData].mystateCity,
        numberofpeople: Data[rowData].numberofpeople > 20 ? 20 : Data[rowData].numberofpeople < 5 ? 5 : Data[rowData].numberofpeople,
    })
}

哦, {}[] :前者是一个空对象,后者是一个空数组。 在 JavaScript 中,数组都是对象,但并非所有对象都是数组。 具体来说,数组具有您关心的所有数组方法,例如push() 如果CountData应该是一个数组,则不能为其分配{} ,因为它缺少数组所需的东西。

继续你的问题的主要部分:


这里的第一个问题是你的界面

interface AllData {
  [value:string]:Row 
}

有一个字符串索引签名,这意味着“一个AllData可以有任意数量的任意string值的键,并且每个键的属性将是一个Row对象”。

请注意,上述定义中的value只是一个占位符,对类型没有任何影响。 它与完全相同的定义

interface AllData {
  [x:string]:Row 
}

无论如何,您的问题是您正在阅读的Data没有那种形状。 它具有完全相同的名称的单个"value" ,并在该键的属性是一个数组Row对象。 含义如下:

let Data: { value: Row[] };

一旦你解决了这个问题,让我们看看对你的代码进行最小的更改以使其正常工作,然后从那里进行改进:

const CountData: Row[] = [];
for (const rowData in Data["value"]) {
    CountData.push({
        eDate: Data["value"][rowData].eDate,
        mystate: Data["value"][rowData].mystate,
        mystateCity: Data["value"][rowData].mystateCity,
        numberofpeople: Data["value"][rowData].numberofpeople > 20 ? 20 :
          Data["value"][rowData].numberofpeople < 5 ? 5 : 
          Data["value"][rowData].numberofpeople,
    })
}

for (const rowData in Data["value"])在所述的迭代Data["value"]数组。 这些将是与数组索引对应的字符串值: "0""1""2"等。通常不建议通过for..in迭代数组,因为您将获得索引作为字符串,可能是乱序的,并且可能有其他意想不到的东西。 不过,它有点工作。

不过,这里的主要问题是:由于您正在迭代Data["value"]的键,您需要通过索引到Data["value"]而不是Data来读取其属性。


让我们停止使用for..of迭代数组索引并使用常规 for 循环:

const CountData: Row[] = [];
for (let i = 0; i < Data["value"].length; i++) {
    CountData.push({
        eDate: Data["value"][i].eDate,
        mystate: Data["value"][i].mystate,
        mystateCity: Data["value"][i].mystateCity,
        numberofpeople: Data["value"][i].numberofpeople > 20 ? 20 : 
          Data["value"][i].numberofpeople < 5 ? 5 : Data["value"][i].numberofpeople,
    })
}

现在保证按顺序发生并且没有任何奇怪的非数字索引。


下一步改进:让我们停止说Data["value"]因为没有理由使用括号属性访问和字符串文字是有效的 JavaScript 标识符。 您可以只使用Data.value

此外,不要多次写入Data.value[i] ,只需将其保存到自己的变量中(嘿,我们现在可以调用该rowData ):

const CountData: Row[] = [];
for (let i = 0; i < Data.value.length; i++) {
    const rowData = Data.value[i]; 
    CountData.push({
        eDate: rowData.eDate,
        mystate: rowData.mystate,
        mystateCity: rowData.mystateCity,
        numberofpeople: rowData.numberofpeople > 20 ? 20 : 
          rowData.numberofpeople < 5 ? 5 : rowData.numberofpeople,
    })
}

接下来,您可以考虑使用for...of循环直接迭代rowData元素,而不必关心它们的数字索引

const CountData: Row[] = [];
for (const rowData of Data.value) { 
    CountData.push({
        eDate: rowData.eDate,
        mystate: rowData.mystate,
        mystateCity: rowData.mystateCity,
        numberofpeople: rowData.numberofpeople > 20 ? 20 : 
          rowData.numberofpeople < 5 ? 5 : 
          rowData.numberofpeople,
    });
}

}


接下来,复制单个属性很好,但是如果您要复制所有或大部分属性,您可以使用对象字面量扩展语法来快速完成(或Object.assign()类似),然后只需重写您要更改的一项属性:

const CountData: Row[] = [];
for (const rowData of Data.value) {
    CountData.push({ 
        ...rowData,
        numberofpeople: rowData.numberofpeople > 20 ? 20 : 
          rowData.numberofpeople < 5 ? 5 : rowData.numberofpeople
    })
}

}


最后,如果您所做的只是遍历一个数组并生成另一个大小完全相同的数组,其中输入中的每个元素在输出中生成一个元素,则您可以完全省去循环和push并使用Array.prototype.map()代替:

const CountData = Data.value.map(rowData => ({
    ...rowData,
    numberofpeople: rowData.numberofpeople > 20 ? 20 : 
      rowData.numberofpeople < 5 ? 5 : rowData.numberofpeople
}));

}


哇! 我认为这是我能做到的。

Playground 链接到代码

暂无
暂无

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

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