export function isNumeric(val: string): boolean {
  return !isNaN(Number(val));
}

export function isNumber(data: any): data is number {
  return typeof data === 'number';
}
export function isNumberFinite(data: any): data is number {
  return isNumber(data) && isFinite(data);
}
export function isBoolean(data: any): data is boolean {
  return typeof data === 'boolean';
}
export function isString(data: any): data is string {
  return typeof data === 'string';
}
export function isArray(data: any): data is any[] {
  return Array.isArray(data);
}
export function isNull(data: any): data is null {
  return data === null;
}
export function isUndefined(data: any): data is undefined {
  return data === undefined;
}
export function isNullOrUndefined(data: any): data is undefined | null {
  return data === undefined || data === null;
}
export function isStringNullOrUndefined(data: any): data is undefined | null {
  return data === 'undefined' || data === 'null' || data === '';
}
export function isObject(data: any): data is any {
  return !isNullOrUndefined(data) && typeof data === 'object' && !isArray(data);
}
export function isInArray(data: any, listElement: any[]): boolean {
  for (let iii = 0; iii < listElement.length; iii++) {
    if (listElement[iii] === data) {
      return true;
    }
  }
  return false;
}

export function isArrayOf<TYPE>(
  data: any,
  typeChecker: (subData: any) => subData is TYPE,
  length?: number
): data is TYPE[] {
  if (!isArray(data)) {
    return false;
  }
  if (!data.every(typeChecker)) {
    return false;
  }
  if (!isUndefined(length) && data.length != length) {
    return false;
  }
  return true;
}
export function isArrayOfs<TYPE, TYPE2, TYPE3>(
  data: any,
  typeChecker: (subData: any) => subData is TYPE,
  typeChecker2?: (subData: any) => subData is TYPE2,
  typeChecker3?: (subData: any) => subData is TYPE3
): data is (TYPE | TYPE2 | TYPE3)[] {
  if (!isArray(data)) {
    return false;
  }
  for (let iii = 0; iii < data.length; iii++) {
    let elem = data[iii];
    if (typeChecker(elem)) {
      continue;
    }
    if (typeChecker2 != undefined && typeChecker2(elem)) {
      continue;
    }
    if (typeChecker3 != undefined && typeChecker3(elem)) {
      continue;
    }
    return false;
  }
  return true;
}

export function isOptionalOf<TYPE>(
  data: any,
  typeChecker: (subData: any) => subData is TYPE
): data is TYPE | undefined {
  return isUndefined(data) || typeChecker(data);
}

export function isOptionalArrayOf<TYPE>(
  data: any,
  typeChecker: (subData: any) => subData is TYPE
): data is TYPE[] | undefined {
  return isUndefined(data) || isArrayOf(data, typeChecker);
}
