Hone logo
Hone
Problems

Type Guarding for Diverse Data Structures

In real-world applications, you often deal with data that can come in various shapes and forms. TypeScript's type system is powerful, but sometimes you need to refine the type of a variable at runtime to ensure you're working with the correct structure. This challenge focuses on implementing custom type guards to safely discriminate between different object types.

Problem Description

You are tasked with building a system that processes different types of user profiles. These profiles can be either AdminProfile or RegularUserProfile. You need to write functions that can safely handle these different profile types by using custom type guards.

What needs to be achieved:

  1. Define interfaces for AdminProfile and RegularUserProfile.
  2. Create a function processUserProfile that accepts a union type of AdminProfile | RegularUserProfile.
  3. Inside processUserProfile, use a custom type guard to determine if the current profile is an AdminProfile or a RegularUserProfile.
  4. Based on the profile type, perform specific actions:
    • If it's an AdminProfile, log a message indicating administrative access and display the admin's unique adminId.
    • If it's a RegularUserProfile, log a message indicating regular user access and display the user's email.

Key requirements:

  • You must define the AdminProfile and RegularUserProfile interfaces.
  • You must implement a custom type guard function, for example, isAdminProfile, that returns true if an object is an AdminProfile and false otherwise.
  • The processUserProfile function should leverage your custom type guard.
  • The output messages should be clear and informative.

Expected behavior:

  • When processUserProfile is called with an AdminProfile, it should log a specific message including the adminId.
  • When processUserProfile is called with a RegularUserProfile, it should log a specific message including the email.

Important edge cases to consider:

  • What happens if an object that is neither an AdminProfile nor a RegularUserProfile is passed to processUserProfile? Your type guard should handle this gracefully.

Examples

Example 1:

Input: An object representing an admin profile.
const admin: AdminProfile = {
  type: "admin",
  userId: 101,
  adminId: "ADM789",
  permissions: ["read", "write"]
};

processUserProfile(admin);
Output:
Processing user profile...
This is an admin profile. Admin ID: ADM789

Explanation: The processUserProfile function receives an AdminProfile. The isAdminProfile type guard correctly identifies it as an admin, and the corresponding log message with the adminId is displayed.

Example 2:

Input: An object representing a regular user profile.
const regularUser: RegularUserProfile = {
  type: "user",
  userId: 202,
  email: "test@example.com",
  creationDate: new Date()
};

processUserProfile(regularUser);
Output:
Processing user profile...
This is a regular user profile. Email: test@example.com

Explanation: The processUserProfile function receives a RegularUserProfile. The isAdminProfile type guard correctly identifies it as a regular user (by returning false), and the corresponding log message with the email is displayed.

Example 3: (Edge Case)

Input: An object that does not conform to either profile type.
const unknownProfile = {
  someOtherProp: "value"
};

processUserProfile(unknownProfile);
Output:
Processing user profile...
Unknown profile type.

Explanation: The processUserProfile function receives an object that doesn't match the structure of either AdminProfile or RegularUserProfile. The type guard should return false, and since there's no specific handler for "unknown" beyond the default, a generic message or an error could be appropriate (here, a simple "Unknown profile type" is shown).

Constraints

  • The userId property in both profile types must be a number.
  • The type property in AdminProfile must be the literal string "admin".
  • The type property in RegularUserProfile must be the literal string "user".
  • adminId must be a string.
  • email must be a string.
  • The solution should be implemented in TypeScript.

Notes

  • Consider using a common property (like type in the examples) to help differentiate between object types.
  • A type guard function typically has a return type of parameterName is Type, where parameterName is the name of the parameter being checked and Type is the specific type it's guarding for.
  • Think about how to safely access properties that are only present on one of the types.
Loading editor...
typescript