简体   繁体   English

在TypeScript中使用变量属性名称定义对象类型

[英]Define Object type with variable properties name in TypeScript

I'm struggling with a React + TypeScript "problem": it actually don't stop my app, but now I've this doubt I want to remove!.. It's more of a question! 我在React + TypeScript的“问题”中苦苦挣扎:它实际上并没有停止我的应用程序,但是现在我想删除这个疑问!..这更多的是问题!

What I would like to achieve is to define the properties name of an object, whereas the properties name are given by variables. 我要实现的是定义对象的属性名称,而属性名称由变量给定。 Let me explain with an example -> https://codepen.io/Gesma94/pen/xmwMzY 让我用一个例子来解释-> https://codepen.io/Gesma94/pen/xmwMzY

/* The 'data' property is "dynamic": it will always have this structure,
 * but the name properties (and the values) may change.
 * The 'mapping' property is used to know the name properties inside 'data'.
 */  
const series = {
  data: [
    {map1: "People reached", map2: 200},
    {map1: "People who called", map2: 117},
    {map1: "Contract signed", map2: 77}
  ],
  mapping: {
    stage: "map1",
    values: "map2"
  }
};

/* This is the actual app. */
const myPar = document.getElementById("myPar");
const { stage: stageLabel, values: valuesLabel} = series.mapping;

series.data.forEach((sample: any, index: number) => {
  myPar.innerHTML = myPar.innerHTML + "<br>" + sample[stageLabel];
});

As you can see, in the forEach I write sample: any . 如您所见,在forEach我编写了sample: any

Now, I know sample has a string (the first one will always be a string ) property which name is map1 , and that's because I retrieved and saved in stageLabel . 现在,我知道sample具有一个string (第一个始终是string )属性,其名称为map1 ,这是因为我检索并保存在stageLabel I also know that the other property is a number (it's always a number ) and its name map2 is saved in valueLabel . 我也知道另一个属性是一个number (始终是一个number ),其名称map2保存在valueLabel

Now, what I'm starving to understand is how to not write sample: any , but define the type of sample using the information I retrieved earlier. 现在,我渴望了解的是如何不编写sample: any ,而是使用我之前检索的信息来定义sample的类型。 Basically, I would like to write something like: sample: {stageLabel: string, valueLabel: number} , but doing this way TypeScript believe sample has the properties stageLabel and valueLabel , since we are in "compile time" and it can't even evaluate the variables. 基本上,我想编写如下sample: {stageLabel: string, valueLabel: number}sample: {stageLabel: string, valueLabel: number} ,但是这样做TypeScript认为sample具有stageLabelvalueLabel属性,因为我们处于“编译时”,甚至不能评估变量。

So, since TypeScript can't know what's inside the variables, I know I can't actually obtain sample: {map1: string, map2: number} , but maybe I can obtain some sort of aliasing. 因此,由于TypeScript无法知道变量内部的内容,因此我知道实际上无法获取sample: {map1: string, map2: number} ,但是也许我可以获得某种别名。 For example, I write sample: {stageLabel: string, valueLabel: number} , and in the rest of the code I use the properties sample.stageLabel and sample.valueLabel . 例如,我编写了sample: {stageLabel: string, valueLabel: number} ,在其余的代码中,我使用了sample.stageLabelsample.valueLabel属性。 Then, when the application is running, those property name are evaluated, so sample.stageLabel is actually sample.map1 . 然后,在应用程序运行时,将评估那些属性名称,因此sample.stageLabel实际上是sample.map1

I hope I've been clear enough to understand my question. 我希望我已经足够清楚地理解我的问题。

Why not actually map your data? 为什么不实际映射您的数据?

 const series = { data: [ {map1: "People reached", map2: 200}, {map1: "People who called", map2: 117}, {map1: "Contract signed", map2: 77} ], mapping: { stage: "map1", values: "map2" } }; const myPar = document.getElementById("myPar"); let mappedData = getMappedData(series.data, series.mapping); // append results mappedData.forEach((record:{stage:string, value:number}) => { myPar.innerHTML = myPar.innerHTML + `<br>${record.stage}: ${record.value}`; }); function getMappedData(data, mapping): {stage:string, value:number}[] { let stageLabel = mapping["stage"]; let valueLabel = mapping["values"]; return data.map(x => { return { stage: x[stageLabel], value: x[valueLabel] }; }) } 
 <p id="myPar"><b>Results:</b></p> 

Note that the compiler already nows that items in mappedData have the type {stage:string, value:number} , so you can omit this when appending and simply write: 请注意,编译器现在已经知道mappedData中的项目的类型为{stage:string, value:number} ,因此您可以在追加时忽略此内容,只需编写即可:

// append results
mappedData.forEach(record => {
  myPar.innerHTML = myPar.innerHTML + `<br>${record.stage}: ${record.value}`;
});

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

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