Example 3

interface User {
    name: string
    surname?: string
    age: number
}

const users: User[] = [{
    name: "alice",
    surname: "zuberg",
    age: 19
}, {
    name: "asuna",
    surname: "yuuki",
    age: 19
}, {
    name: "kazuto",
    surname: "Kirigaya",
    age: 17
}]
import { ProjectError, wrap, capsule, unwrap } from '@sirutils/core'

const getUser = wrap((name: User["name"]) => {
    const found = users.find(user => user.name === name)

    if(!found) {
        return ProjectError.create("?not-found", "user not found").throw()
    }

    return found
}, "?get-user")

const sayHi = capsule((name: string) => {
    const user = unwrap(getUser(name))

    if(!user.surname) {
        return ProjectError.create("?unexpected", `user: ${user.name} surname is undefined`).throw()
    }

    return `Hi ${user.name} ${user.surname}`
}, "?say-hi")

console.log(sayHi("alice"))

Let's break down the code step by step:

1. Importing Utility Functions

import { ProjectError, wrap, capsule, unwrap } from '@sirutils/core'

Here, you're importing four utility functions: ProjectError, wrap, capsule, and unwrap from the @sirutils/core package. These functions are used for error handling and function encapsulation.

2. Wrapping the getUser Function

const getUser = wrap((name: User["name"]) => {
    const found = users.find(user => user.name === name)

    if(!found) {
        return ProjectError.create("?not-found", "user not found").throw()
    }

    return found
}, "?get-user")
  • Purpose: The getUser function is wrapped with the wrap utility to add additional functionality, such as logging or error handling, under the name "?get-user".
  • Functionality:
    • It takes a name parameter (expected to be of type User["name"]).
    • It searches for a user in the users array whose name matches the provided name.
    • If the user is not found, it creates and throws a ProjectError with the type "?not-found" and the message "user not found".
    • If the user is found, it returns the user object.

3. Encapsulating the sayHi Function

const sayHi = capsule((name: string) => {
    const user = unwrap(getUser(name))

    if(!user.surname) {
        return ProjectError.create("?unexpected", `user: ${user.name} surname is undefined`).throw()
    }

    return `Hi ${user.name} ${user.surname}`
}, "?say-hi")
  • Purpose: The sayHi function is encapsulated with the capsule utility to similarly add functionality, like error management, under the name "?say-hi".
  • Functionality:
    • It takes a name parameter of type string.
    • It calls the getUser function with the provided name and uses unwrap to extract the result. If the result is an error, unwrap would handle that error.
    • If the user object doesn't have a surname, it creates and throws a ProjectError with the type "?unexpected" and a message indicating the missing surname.
    • If the surname is present, it returns a greeting string, Hi {user.name} {user.surname}.

4. Running the sayHi Function

console.log(sayHi("alice"))
  • Purpose: This line calls the sayHi function with the argument "alice" and logs the result to the console.
  • Expected Behavior:
    • If a user named "alice" is found and has a surname, it will print something like Hi Alice Smith to the console.
    • If the user "alice" is not found or if her surname is missing, it will throw an error.

Summary

This code demonstrates a structured way of handling errors using custom error objects (ProjectError), function wrapping (wrap), and encapsulation (capsule). The functions are designed to fail gracefully by throwing specific errors when something goes wrong, ensuring that error handling is centralized and consistent across the codebase.