typescript 如何在使用reduce方法时无类型抱怨地遍历对象?

t5fffqht  于 2022-12-19  发布在  TypeScript
关注(0)|答案(1)|浏览(152)

我尝试将以下数据[{ year: "yyyy" }, { month: "mm" }, { day: "dd" }]转换为{ year: "yyyy", month: "mm", day: "dd" }。因此,在下面的代码库中,我使用了reduce方法,但在curr上收到类型脚本错误消息,显示“Type '{ [x:字符串]:任意;}“不是数组类型或字符串类型。”同样在acc[key]上,我收到另一条错误消息“元素隐式具有”any“类型,因为类型为”any“的表达式不能用于索引类型”{}“”。在其他IDE中,我没有收到类型错误,但在控制台上收到此错误“TypeError:迭代不可迭代示例的尝试无效。为了可迭代,非数组对象必须具有Symbol.iterator方法。”我知道有其他方法可以操作数据,例如for循环,但我想知道如何使用reduce方法使其工作。https://codesandbox.io/s/sharp-glitter-43ql15?file=/src/App.tsx:0-550

import "./styles.css";
import { useEffect } from "react";

export default function App() {
  interface IData {
    day: string;
    month: string;
    year: string;
  }

  let data = [{ year: "yyyy" }, { month: "mm" }, { day: "dd" }];

  const updateData = (): IData => {
    const updatedData = data.reduce((accu, curr: { [x: string]: any }) => {
      for (const [key, val] of curr) {
        accu[key] = val;
      }
      return accu;
    }, {});
    console.log(updatedData);
    return updatedData;
  };

  return <div className="App"></div>;
}
oknwwptz

oknwwptz1#

  • 在TypeScript中使用any会破坏TypeScript的用途,因为您会失去类型安全。最好尽可能避免使用any,这样您将能够在编译时而不是运行时更可靠地调试内容。在这里,属性的值是 * string *,因此您可以改用它。或者,您可以完全省略显式注解,TypeScript将自己很好地推断它。
  • 迭代时,每个被迭代的对象都在curr参数中,它不是一个数组;它是一个像{ year: "yyyy" }这样的普通对象,所以,尝试用for..of迭代对象是没有意义的,使用Object.entries来迭代每个键和每个值。
for (const [key, val] of Object.entries(curr)) {
  • 但是返回的对象仍然不能被正确地类型化,虽然可以用泛型调用.reduce来指示累加器的类型,因为累加器直到最后一次迭代才被完全构造。您必须使用Partial-然后您必须在最后将其强制转换回完整的IData。问题是所有迭代对象键的方法都将导致键被类型化为string,即使对象的键更具体(如year | month | day)-因此某些类型的强制转换在某些地方是必要的(或者您必须在运行时显式地检查每个可能的键)。

与其纠结于.reduce的类型,不如考虑执行以下操作:

const updateData = () => Object.assign({}, ...data) as IData;

如果您真的必须使用.reduce,它看起来应该是这样的:

interface IData {
    day: string;
    month: string;
    year: string;
}
let data = [{ year: "yyyy" }, { month: "mm" }, { day: "dd" }] as const;
const updateData = (): IData => {
    const updatedData = data.reduce<Partial<IData>>((accu, curr) => {
        for (const [key, val] of Object.entries(curr)) {
            if (key !== 'year' && key !== 'month' && key !== 'day') {
                throw new Error('Non-matching key found');
            }
            // eslint-disable-next-line no-param-reassign
            accu[key] = val;
        }
        return accu;
    }, {});
    return updatedData as IData;
};

相关问题