0

I have this array of records which is being duplicated for each users's courses:

id  name  courseId  title   
1   user 1  11  course A
1   user 1  22  course B
2   user 2  33  course C
3   user 3  44  course D

But actually I want response like this, I want to remove the duplicated record of user and put courses as an array against each user

[
  {
    "id": 1,
    "name": "user 1",
    "courses": [
      {
        "courseId": 11,
        "title": "course A",
      },
      {
        "courseId": 22,
        "title": "course B",
      }
    ]
  },
  {
    "id": 2,
    "name": "user 2",
    "courses": [
      {
        "courseId": 33,
        "title": "course C",
      }
    ]
  },
  {
    "id": 3,
    "name": "user 3",
    "courses": [
      {
        "courseId": 44,
        "title": "course D",
      }
    ]
  }
] 

I am very new to Typescript, how can I achieve this response in an optimized way?

1 Answer 1

1

You can define 2 types for User and Course, and then group them together with a new type called UserWithCourses

For the array mapping logic, you can use reduce

type Course = {
    courseId?: number,
    title?: string
}

type User = {
    id: number,
    name: string
}

const input: (User & Course)[] = [{
    id: 1,
    name: "user 1",
    courseId: 11,
    title: "course A"
}, {
    id: 1,
    name: "user 1",
    courseId: 22,
    title: "course B"
}, {
    id: 2,
    name: "user 2",
    courseId: 33,
    title: "course C"
}, {
    id: 3,
    name: "user 3",
    courseId: 44,
    title: "course D"
}, { id: 4, name: "user 4" }]

type UserWithCourses = User & { courses?: Course[] | null }

const output: UserWithCourses[] = input.reduce((result: UserWithCourses[], item: User & Course): UserWithCourses[] => {
    const user: UserWithCourses | undefined = result.find(({ id }) => item.id === id)

    const course: Course = {
                courseId: item.courseId,
                title: item.title
            }

    if(user && user.courses) {
        user.courses.push(course)
    } else {
        result.push({
            id: item.id,
            name: item.name,
            courses: item.courseId ? [course] : null
        })
    }
    return result
}, [])

console.log(output)

Playground

Sign up to request clarification or add additional context in comments.

8 Comments

There is also a case with there will be no course assigned to a user, but the user will appear in list. e.g add this record to the input array aswell: { id: 4, name: "user 4" }
You can make courseId and title in Course optional with ?. By the way, I also updated my answer for the sake of your requirement @StormTrooper
Cant we avoid the code repetition?
Also is this possible to create a single interface for this, i stead of type Course = { courseId?: number, title?: string } type User = { id: number, name: string }
If we try to combine Course and User, it will cause type duplication in UserWithCourses.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.