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

时间:2018-12-13 09:08:28

标签: javascript typescript

我正在为React + TypeScript的“问题”而苦苦挣扎:它实际上并没有停止我的应用程序,但是现在我想删除这个疑问!..更多的是问题!

我要实现的是定义对象的属性名称,而属性名称由变量给定。让我用一个例子解释-> 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];
});

如您所见,在forEach中,我写着sample: any

现在,我知道sample有一个string属性(第一个永远是string),这是因为我检索并保存了在map1中。我还知道另一个属性是stageLabel(始终是number),其名称number保存在map2中。

现在,我渴望了解的是如何不写valueLabel,而是使用我之前检索的信息来定义sample: any的类型。 基本上,我想写一些类似的内容:sample,但是这样做是因为TypeScript相信sample: {stageLabel: string, valueLabel: number}具有属性samplestageLabel,因为我们处于“编译时间”。甚至无法评估变量。

因此,由于TypeScript无法知道变量内部的内容,所以我知道实际上无法获得valueLabel,但也许我可以获得某种别名。 例如,我编写了sample: {map1: string, map2: number},在其余代码中,我使用了属性sample: {stageLabel: string, valueLabel: number}sample.stageLabel。然后,在应用程序运行时,将评估那些属性名称,因此sample.valueLabel实际上是sample.stageLabel

我希望我已经足够清楚地理解我的问题。

1 个答案:

答案 0 :(得分:1)

为什么不真正映射您的数据?

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>

请注意,编译器已经知道mappedData中的项目具有类型{stage:string, value:number},因此您可以在追加时忽略此内容,只需编写:

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