/**
 * You can use this `get` function to retrieve a nested property from an object by chaining
 * the keys with dots in the `path` parameter. For example:
 * ```typescript
 * const obj = {
 *   foo: {
 *     bar: {
 *       baz: 'Hello, World!'
 *     }
 *   }
 * };
 *
 * console.log(get(obj, 'foo.bar.baz'));                // Output: 'Hello, World!'
 * console.log(get(obj, 'foo.bar.baz', 'Default'));     // Output: 'Hello, World!'
 * console.log(get(obj, 'foo.bar.qux', 'Default'));     // Output: 'Default'
 * ```
 * @param obj the object to retrieve the nested property from
 * @param path the path to the nested property
 * @param defaultValue the default value to return if the nested property does not exist
 * @returns the nested property if it exists, otherwise the default value
 */
export function get<T, K>(obj: T, path: string, defaultValue?: K): any {
  // Split the path string into individual keys
  const keys = path.split('.');

  // Loop through each key to access nested properties
  let value = obj;
  for (const key of keys) {
    if (value == null) {
      // If the nested property is null or undefined, return the default value
      return defaultValue;
    }
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    value = value[key];
  }

  // If the final nested property exists, return its value
  return value === undefined || value === null ? defaultValue : value;
}
