为什么打字稿坚持隐含的类型?

Why is typescript insisting on a type that is implied?

@ts-ignore 之后的行中,我将一个新的键值对添加到以前看起来像这样的对象:{id:string, text:string}

如您所见:

Webstorm 告诉我类型应该是 {id:string, text:string}

我想知道,为什么 TypeScript 坚持这样做? 我从未声明对象必须只有这两个值。

代码和背景

    const goals = COURSE_DATA.map((course) => {
        // @ts-ignore
        course.goals.forEach(g => g.course = course.title)
        return course.goals;
      }).reduce((accGoals, curGoals) => {
        let updatedGoals = curGoals;
        for (let goal of curGoals){
          updatedGoals.concat(goal);
        }
        return accGoals.concat(updatedGoals);
      }, [])

这个函数的目的是从它们的父课程对象中取出目标对象数组,并将它们覆盖到一个目标对象数组中。 基本上把 [{[{}]}] 变成 [{}]

仅供参考,这是父对象数组的一个峰值:

const COURSE_DATA = [
    {
        id: 'c1', title: 'Ionic + React - The Practical Guide', enrolled: new Date("03/05/2121"), goals: [{
            id: "c1g1",
            text: "Complete Course"
        }, {
            id: "c1g2",
            text: "Learn Something"
        }]
    },
]

后来,我决定最终目标数组需要包含每个目标的父课程名称:

 // @ts-ignore
        course.goals.forEach(g => g.course = course.title)

代码在 @ts-ignore 中做到了这一点,但我想了解为什么 TypeScript 会抱怨,对象中当然没有键,为什么显然应该有。

Playground

TypeScript 正在从您的 COURSE_DATA 对象推断类型。因为它是显式定义的,所以它假定这也是您的对象的确切类型结构。如果您希望它更灵活,请使用接口来声明额外的字段。

如果你想访问 titlecourse 字段,你应该在某处定义它的类型,这就是 TypeScript 的全部思想。否则你只是在类型系统中进进出出,如果你仔细想想这没有多大意义。

此更新后的代码不再需要 @tsignore:

const goals = COURSE_DATA.map((course) => {
    return course.goals.map((goals) => {
        return {...goals, course: course.title}
    });
  }).reduce((accGoals, curGoals) => {
    let updatedGoals = curGoals;
    for (let goal of curGoals){
      updatedGoals.concat(goal);
    }
    return accGoals.concat(updatedGoals);
  }, [])