Проблема

Реализовать Absolute тип. Он принимает string, number или bigint. Результатом должно быть положительное число в виде строки. Например:

type Test = -100;
type Result = Absolute<Test>; // expected to be "100"

Решение

Один из способов взять число по модулю - это конвертировать число в строку и убрать знак “-“. Я не шучу, в буквальном смысле убрать знак “-“ со строки.

Начнём с проверки, а есть ли знак “-“ в начале строки. Если да, выводим остальную часть строки без знака “-“, используя условные типы. В случае, знака “-“ нету, значит у нас положительное число, поэтому возвращаем его без изменений.

type Absolute<T extends number | string | bigint> = T extends `-${infer N}`
  ? N
  : T;

Таким образом, если укажем T = "-50", это совпадёт с нашим шаблоном -<N>, где N станет “50” и мы его вернём.

Но, мы видим, что некоторые из тестов по прежнему не проходят. Причина этому заключается в том, что мы не всегда возвращаем строки. Например, передавая положительное число, оно не совпадёт со строкой в условном типе и вернёт число, а нужно строку.

Починим это, обернув T в строчный тип-литерал, перед тем как его возвращать:

type Absolute<T extends number | string | bigint> = T extends `-${infer N}`
  ? N
  : `${T}`;

Всё ещё падают тесты… Мы не обрабатываем случай, когда T это отрицательное число. Число не совпадёт со строкой в условном типе (снова), выведение не сработает и мы вернём отрицательное число, только в строке. Чтобы обработать этот случай, обернём T в строчный тип-литерал и в начале:

type Absolute<T extends number | string | bigint> = `${T}` extends `-${infer N}`
  ? N
  : `${T}`;

В результате, мы получили тип, который принимает number, string или bigint и конвертирует в строку. После приведения к строке, он выводит часть без знака “-“ и возвращает её, иначе, возвращает входной параметр без изменений.

Что почитать