Вывод типа при использовании сложной проверки "isEmpty" - PullRequest
0 голосов
/ 06 декабря 2018

У меня есть следующая функция, которая работает как ramdas isEmpty , но с учетом моих собственных потребностей:

/**
 * Checks if a value is empty.
 * It will return true for the following cases:
 * null, undefined, empty string, empty Set, empty Map, an object without properties.
 * @param input Can be any value.
 * @example
 *
 *     isEmpty([1, 2, 3]); //=> false
 *     isEmpty([]); //=> true
 *
 *     isEmpty(''); //=> true
 *
 *     isEmpty(null); //=> true
 *     isEmpty(undefined); //=> true
 *
 *     isEmpty({}); //=> true
 *
 *     isEmpty(new Set([1, 2, 3])); //=> false
 *     isEmpty(new Set()); //=> true
 *
 *     isEmpty(0); //=> false
 *
 *     isEmpty(new Date()); //=> true
 *     isEmpty(Date.now()); //=> false
 */
export const isEmpty = (input: any): boolean => {
  const isMapOrSet = input instanceof Map || input instanceof Set;
  return input === null
    || input === undefined
    || (input instanceof String ? input.length > 0 : false)
    || (isMapOrSet ? input.size === 0 : false)
    || (!isMapOrSet && input instanceof Object ? Object.keys(input).length === 0 : false);
};

Использование этой функции довольно просто, но я недоволенboolean тип возвращаемого значения, поскольку TypeScript не может определить нулевые проверки, предоставляемые этой функцией.

Например, следующий код вполне подходит, но TypeScript будет жаловаться на возможное значение NULL при вызове someResult[0].

const someResult: [] | null = getStuffFromAPI();
const x = isEmpty(someResult)
? {}
: someResult[0]; // TypeScript will complain about a possible _null_ here.

Итак, вопрос: Как улучшить сигнатуру функции, чтобы TypeScript мог правильно определить тип возвращаемого значения?

Я пытался смоделировать тип возвращаемого пользователем значенияиспользуя условные типы , но я не мог понять, как это правильно.

Чтобы сделать на 100% понятным то, что я ищу, вот некоторый псевдокод (обратите внимание, что HasNoElements и IsEmpty не существуют в TS):

type IsEmpty<T> =
  T extends null | undefined ? true :
  T extends Map & HasNoElements ? true :
  T extends Set & HasNoElements ? true :
  T extends String & IsEmpty ? true :
  T extends Object & IsEmpty ? true :
  false;

Возможно, я обдумываю это, но я бы хотел немного расширить свой кругозор.

1 Ответ

0 голосов
/ 16 апреля 2019

Эта проблема была решена с помощью улучшенного вывода типов для обобщений в TypeScript 3.4 .Таким образом, в моем примере выше я в основном получаю все правильные сигнатуры типов, которые я хотел получить «бесплатно».

...