0

这是我的代码:

interface Siswa {
  name: string,
  points: { a: number, b: number, c: number, d?: number, e?: number }
}

function find_average_points(data: Array<Siswa>): Array<{name: string, average: number}> {
  let returned_array: Array<{name: string, average: number}> = [];
  data.forEach((item: Siswa) => {
    let sum: number = 0;
    let keys = Object.keys(item.points);
    keys.forEach((key: any) => sum+=item.points[key]);
    returned_array.push({name: item.name, average: (sum/keys.length)});
  });
  return returned_array;
}

当我在 JavaScript 中尝试这个函数时,它运行正确并且结果是我想要的,但是在 TypeScript 中,我在item.points[key]. 它说:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ a: number; b: number; c: number; d?: number | undefined; e?: number | undefined; }'.
  No index signature with a parameter of type 'string' was found on type '{ a: number; b: number; c: number; d?: number | undefined; e?: number | undefined; }'

我不知道这意味着什么。

4

2 回答 2

3

使用Object.keys()返回类型string[](如本注释中所述)。相反,您可以为points对象中的已知键创建数组,使用它们来构建您的类型,然后在对值求和时遍历这些键:

TS Playground 链接

const definitePoints = ['a', 'b', 'c'] as const;
const maybePoints = ['d', 'e'] as const;

type Points = (
  Record<typeof definitePoints[number], number>
  & Partial<Record<typeof maybePoints[number], number>>
);

interface Siswa {
  name: string,
  points: Points;
}

interface SiswaAverage {
  name: string;
  average: number;
}

function find_average_points (data: Array<Siswa>): Array<SiswaAverage> {
  const result: Array<SiswaAverage> = [];

  for (const {name, points} of data) {
    let sum = 0;
    let count = 0;

    for (const point of [...definitePoints, ...maybePoints]) {
      const value = points[point];
      if (typeof value !== 'number') continue;
      sum += value;
      count += 1;
    }

    result.push({name, average: sum / count});
  }

  return result;
}
于 2021-11-26T05:56:26.240 回答
1

您可以结合使用 keyof 和 null 检查来解决问题。

    interface Points { a: number, b: number, c: number, d?: number, e?: number } // only did to use keyof

interface Siswa {
  name: string,
  points: Points
}

function find_average_points(data: Array<Siswa>): Array<{name: string, average: number}> {
  let returned_array: Array<{name: string, average: number}> = [];
  data.forEach((item: Siswa) => {
    let sum: number = 0;
    let keys = Object.keys(item.points) as (keyof Points)[]; // use this if you know you wont add extra non number properties in Point 

    keys.forEach((key) => sum+=item.points[key] ?? 0); // for d and e with are optional
    returned_array.push({name: item.name, average: (sum/keys.length)});
  });
  return returned_array;
}
let obj: Siswa = { name: 'Paris', points: { a: 2 , b:2, c: 4, d: 4 }} // can not add random stuff type safe

console.log(find_average_points([obj]))
于 2021-11-26T05:22:22.013 回答