JS helper functions

Igor22.2.2026

A collection of some helpful JS helper functions.

1. Sorts an array of objects based on a specified key, order (ascending or descending), and case sensitivity

typescriptconst sort = (
  array: Array<any>,
  key: string,
  order: string = "asc",
  ignoreCase: boolean = true,
) => {
  return key && array && Array.isArray(array)
    ? array.sort((a: any, b: any) => {
        let aValue = a[key];
        let bValue = b[key];

        if (
          ignoreCase &&
          typeof aValue === "string" &&
          typeof bValue === "string"
        ) {
          aValue = aValue.toLowerCase();
          bValue = bValue.toLowerCase();
        }

        if (aValue > bValue) {
          return order === "asc" ? 1 : -1;
        }

        if (aValue < bValue) {
          return order === "asc" ? -1 : 1;
        }

        return 0;
      })
    : array;
};

2. Formats an address string by capitalizing the first letter of each word, except for certain lowercase words (e.g. "og", "i", "på") and house numbers (e.g. "14E", "43A", "12-14B")

typescriptconst formatAddress = (address: string) => {
  const lowercaseWords = [
    // Norwegian
    "og",
    "i",
    "på",
    "av",
    "gate",
    "veien",
    "vei",
    "gata",
    "veg",
    "industrivei",
    "industriveg",
    "allé",
    // Swedish
    "och",
    "i",
    "på",
    "av",
    "gatan",
    "vägen",
    "väg",
    // Danish
    "og",
    "i",
    "på",
    "af",
    "gade",
    "vej",
    // Finnish
    "ja",
  ];

  return address
    .toLocaleLowerCase("sv-SE")
    .split(/\s+/)
    .map((word, index) => {
      // House numbers like 14E, 43A, 12-14B
      if (/\d/.test(word)) {
        return word.toUpperCase();
      }
      // Keep words from lowercaseWords list in lowercase, except if it's the first word in the address
      if (index !== 0 && lowercaseWords.includes(word)) {
        return word;
      }
      // Capitalize the first letter of each word
      return word
        .split("-")
        .map(
          (part) => part.charAt(0).toLocaleUpperCase("sv-SE") + part.slice(1),
        )
        .join("-");
    })
    .join(" ")
    .trim();
};

3. Truncates a string to a specified length and adds "..." at the end if it exceeds that length

typescriptconst truncateString = (str: string, num: number) => {
  if (str) {
    if (str.length <= num) {
      return str;
    }
    return str.slice(0, num) + "\u2026";
  }
  return "";
};

4. Formats a date string to "YYYY-MM-DD" format, e.g. "2024-06-01T12:00:00Z" becomes "01.06.2024" or "01.06.2024 12:00"

typescriptconst formatDate = (date: string, withTime: boolean = false) => {
  let newDate = new Date(date);
  let dateString = newDate.toLocaleDateString("nb-NO", {
    day: "2-digit",
    month: "2-digit",
    year: "numeric",
  });

  if (withTime) {
    let timeString = newDate.toLocaleTimeString("nb-NO", {
      hour: "2-digit",
      minute: "2-digit",
    });

    return `${dateString} ${timeString}`;
  }

  return dateString;
};

5. Formats a date string to "YYYY-MM-DD HH:mm:ss" format, e.g. "2024-06-01T12:00:00Z" becomes "2024-06-01 12:00:00"

typescriptconst dateAndTimeWithoutTimeZone = (dateAndTime: string) => {
  let date = new Date(dateAndTime);
  return date
    .toISOString()
    .replace("T", " ")
    .replace(/\.\d{3}Z$/, "");
};

6. Formats a number with spaces as thousand separators, e.g. 1000000 becomes "1 000 000"

typescriptconst numberWithSpaces = (value: number) => {
  return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
};

7. Validates an object by checking for missing or empty values, and optionally validating email formats. It can also ignore specified keys and print logs of the validation process.

javascriptconst validateObject = (
  obj: Record<string, any>,
  options: {
    path?: string,
    ignoreKeys?: string[],
    printLogs?: boolean,
    setErrors?: React.Dispatch<React.SetStateAction<string[]>>,
    collectedErrors?: string[]
  } = {}
) => {
  const { path = '', ignoreKeys = [], printLogs = false, setErrors, collectedErrors = [] } = options;
  const validateEmail = (val:string) => {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(val)
  }

  for (const key in obj) {
    const value = obj[key]
    const currentPath = path ? `${path}.${key}` : key

    if (typeof value === 'object' && value !== null) {
      validateObject(value, { path: currentPath, ignoreKeys, printLogs, setErrors, collectedErrors })
    } else {
      if (printLogs) {
        console.log(`👀 Validating ${currentPath}: ${value}`)
      }
      const isEmptyString = typeof value === 'string' && value.trim() === ''
      const isMissing = value === undefined || value === null || isEmptyString
      if (isMissing && !ignoreKeys.includes(currentPath)) {
        if (printLogs) {
          console.error(`❌ Validation failed for: ${currentPath}: value is required`)
        }
        collectedErrors.push(currentPath)
      } else if (key.toLowerCase().endsWith('email') && !validateEmail(value) && !ignoreKeys.includes(currentPath)) {
        if (printLogs) {
          console.error(`❌ Validation failed for: ${currentPath}: invalid email format`)
        }
        collectedErrors.push(currentPath)
      }
    }
  }
  setErrors && setErrors(collectedErrors)
  if (collectedErrors.length > 0) return false
  if (printLogs) {
    console.log('✅ Validation passed: ', collectedErrors.length === 0)
  }
  return collectedErrors.length === 0
}