Welcome to today's lesson on applying data filtering and aggregation in a real-world scenario using a user management system. We'll start by building a foundational structure that can handle basic user operations. Then, we'll expand it by introducing more advanced functionalities that allow filtering and aggregating user data.
In our starter task, we will implement a class that manages basic operations on a collection of user data, specifically handling adding new users, retrieving user profiles, and updating user profiles.
Here are the starter task methods with TypeScript type annotations:
addUser(userId: string, age: number, country: string, subscribed: boolean): boolean
- adds a new user with the specified attributes. Returnstrue
if the user was added successfully andfalse
if a user with the sameuserId
already exists.getUser(userId: string): UserProfile | null
- returns the user's profile as an object if the user exists; otherwise, returnsnull
.updateUser(userId: string, age: number | null, country: string | null, subscribed: boolean | null): boolean
- updates the user's profile based on non-null
parameters. Returnstrue
if the user exists and was updated,false
otherwise.
The UserProfile
data type is an interface that defines the structure of a user's profile, consisting of three properties: age
which is a number
, country
which is a string
, and subscribed
which is a boolean
. This interface ensures that every user profile adheres to this defined structure.
The TypeScript implementation of our starter task is shown below:
This implementation covers all our starter methods. Let's move forward and introduce more complex functionalities.
With our foundational structure in place, it's time to add functionalities for filtering user data and aggregating statistics.
Here are the new methods to implement with TypeScript type annotations:
filterUsers(minAge: number | null, maxAge: number | null, country: string | null, subscribed: boolean | null): string[]
:- Returns the list of user IDs that match the specified criteria. Criteria can be
null
, meaning that the criterion should not be applied during filtering.
- Returns the list of user IDs that match the specified criteria. Criteria can be
aggregateStats(): { totalUsers: number; averageAge: number; subscribedRatio: number }
- returns statistics in the form of an object:totalUsers
: Total number of usersaverageAge
: Average age of all users (rounded down to the nearest integer)subscribedRatio
: Ratio of subscribed users to total users (as a float with two decimals)
This method filters users based on the criteria provided. Let's see how it works in TypeScript:
- The
filterUsers
method filters users based onminAge
,maxAge
,country
, andsubscribed
status criteria. - It iterates over the
users
object and checks each user's profile against the provided criteria. - Users who meet all the criteria are added to the
filteredUsers
list, which is then returned. - The example usage demonstrates the addition of users and how to filter them based on different criteria.
This method aggregates statistics from the user profiles. Let's implement it in TypeScript:
- The
aggregateStats
method calculates aggregate statistics about users and returns them as an object. - It begins by determining
totalUsers
, the total number of users. - If no users exist, it returns an object with all statistics set to zero.
- With users present, it calculates
totalAge
by summing up all users' ages and counts how many aresubscribedUsers
. - Next, it computes
averageAge
by dividingtotalAge
bytotalUsers
and rounding down to the nearest integer. - It also calculates
subscribedRatio
by dividingsubscribedUsers
bytotalUsers
, rounding the result to two decimal places. - The resulting object includes
totalUsers
,averageAge
, andsubscribedRatio
.
Here's the complete UserManager
class with all methods, including the new ones for filtering and aggregation, all implemented in TypeScript:
Great job! Today, you've learned how to effectively handle user data in TypeScript by implementing advanced functionalities like filtering and aggregation on top of a basic system. TypeScript's robust typing aids significantly in data management and helps catch potential errors during development. This is a critical skill in real-life software development, where you often need to extend existing systems to meet new requirements.
I encourage you to practice solving similar challenges to solidify your understanding of data filtering and aggregation with strong type support. Happy coding, and see you in the next lesson!
