javascripttypescripttype-safety

A better way to check for non falsy values in JS/TS?


I am posting to see if anyone has a cleaner way of checking for non-false values in JS/TS files.

Over the years, I've had several attempts of writing cleaner if statements to check for non-falsy values as it triggers me how they all do the same thing but are pretty lengthy and end up taking half of some code files.

I tried creating functions and typing them in different ways to encapsulate logging and then throwing errors, but TS doesn't accept this as a safe check. So far, the only thing satisfying the check is a standard if statement, with the error thrown directly in the body.

Is there no better, less verbose way of handling these repetitive checks while maintaining safety?

Stadandard checks

 // Not falsy check
     if (!plan) {
        Log.log.stripe_webhook("Plan not found");
        throw new Error("Plan not found");
      }

  // Another not falsy check
      if (!currentUser.email) {
          Log.log.stripe_webhook("Current user does not have an email");
         throw new Error("Current user does not have an email");
       }

Things I've tried

Helper functions. I tried several ones over time, but here is a basic example, which TS doesn't accept.

// Function to ensure no false values. TS does not accept this as safe.
            function ensureNotFalsy(
              condition: any,
              errorMessage: string
            ): void {
              if (!condition) {
                Log.log.stripe_webhook(errorMessage);
                throw new Error(errorMessage);
              }
            }

            // Not falsy checks
            ensureNotFalsy(orgRef, "Organization reference not found");
            ensureNotFalsy(orgRef?.organization, "Organization not found");
            ensureNotFalsy(
              orgRef!.organization!.id,
              "Organization ID not found"
            );

  // ...Code below will still throw errors saying these checked values could be undefined.

Adding the errors and handling in a const. Doesn't work either. TS, seems to require the error to be thrown in each if statement.

 // Put logic in a const. TS doesn't recognize it as a safe.
        const throwError = (message: string) => {
            Log.log.stripe_webhook(message);
            throw new Error(message);
         };

          // Checks to ensure not falsy. Doesn't work with TS.
          if (!plan) throwError("Plan not found");
          if (!currentUser.email)
          throwError("Current user does not have an email");

  // ...Code below will still throw errors saying these checked values could be undefined.

Screenshot example


Solution

  • Assertion functions are designed for exactly this purpose. Simply use asserts condition instead of void for the return type of ensureNotFalsy, and it should work.

    Here is an example:

    function ensureNotFalsy(
      condition: any,
      errorMessage: string
    ): asserts condition {
      if (!condition) {
        throw new Error(errorMessage);
      }
    }
    
    const f = (orgRef: {organization?: {id?: string}} | null) => {
      ensureNotFalsy(orgRef, "Organization reference not found");
      ensureNotFalsy(orgRef.organization, "Organization not found");
      ensureNotFalsy(
        orgRef.organization.id,
        "Organization ID not found"
      );
    }
    

    Playground link