export function nonnull<T>(something: T): T | undefined {
    return something === null ? undefined : something;
  }
  
  export function notNull<T>(something: T): boolean {
    return something !== null && typeof something !== "undefined" && something !== undefined;
  }
  
  export function or<T>(something: T | null | undefined, somethingElse: any): T {
    return something ? something : (somethingElse as T);
  }
  
  export function coalesce<T>(first: T, ...other: T[]): T {
    if (first) return first;
    other.forEach(thing => {
      if (thing) return thing;
    });
    return first;
  }
  
  export function extract<T>(obj: Object, hierarchy: string, otherwise: T): T {
    if (!notNull(obj) || !notNull(hierarchy)) {
      return otherwise;
    }
    let path = hierarchy.split(".");
    let last = obj;
    for (let i = 0; i < path.length; i++) {
      let next = path[i];
      if (last.hasOwnProperty(next)) {
        last = last[next as keyof Object];
      } else {
        return otherwise;
      }
    }
    return last as T;
  }
  
  export function has(obj: Object, hierarchy: string): boolean {
    if (!notNull(obj) || !notNull(hierarchy)) {
      return false;
    }
    let path = hierarchy.split(".");
    let last = obj;
    for (let i = 0; i < path.length; i++) {
      let next = path[i];
      if (last.hasOwnProperty(next)) {
        last = last[next as keyof Object];
      } else {
        return false;
      }
    }
    return true;
  }
  
  export function hasAny<T>(list?: T[] | null): boolean {
    return or(list, []).length > 0;
  }
  