Comments 6
BuildHexString
не совсем соответствует своему jsdoc, он здесь дает строки длиной от 1 до N включительно. Если нужна длина ровно N, то надо убрать Result |
из рекурсивного вызова. Ну и разумеется, тут не надо возиться с созданием кортежа и последующим join, проще сразу конкатенировать шаблонную строку, длина всё равно считается отдельным кортежем Count:
type _BuildHexString<N extends number, Result extends string, Count extends unknown[]> = Count['length'] extends N
? Result
: _BuildHexString<N, Result | `${Result}${Digit}`, [1, ...Count]>;
Привязываясь к Result разве не получится такая штука для N 3 и 4 соответственно?
type Step3 = Digit | `${Digit}${Digit}` | `${Digit | `${Digit}${Digit}`}${Digit}`
type Step4 = Digit | `${Digit}${Digit}` | `${Digit | `${Digit}${Digit}`}${Digit}` | `${Digit | `${Digit}${Digit}` | `${Digit | `${Digit}${Digit}`}${Digit}`}${Digit}`
Если оставить только ${Result}${Digit}
type Step3_1 = `${Digit | `${Digit}${Digit}`}${Digit}`
type Step4_1 = `${Digit | `${Digit}${Digit}` | `${Digit | `${Digit}${Digit}`}${Digit}`}${Digit}`
Все эти типы описывают нужную строку. Но я изначально хотел сделать:
type Step3_my = `${Digit}` | `${Digit}${Digit}` | `${Digit}${Digit}${Digit}`
type Step4_my = `${Digit}` | `${Digit}${Digit}` | `${Digit}${Digit}${Digit}` | `${Digit}${Digit}${Digit}${Digit}`
Тут на самом деле без разницы. TS всё равно превращает это в объединение строковых литералов, потому что Digit - конечный набор значений. Просто делается декартово произведение, и всё. Посмотрите в плейграунде результат, по наведению мыши.
Можно никуда не смотреть, это еще в документации написано, что шаблоны строковых литералов - это объединение всех строковых литералов обусловленных типами входящими в шаблон.
Да, можно так сделать. Но мне хотелось именно такое объединение получить:
type Step4_my = `${Digit}` | `${Digit}${Digit}` | `${Digit}${Digit}${Digit}` | `${Digit}${Digit}${Digit}${Digit}`
При его строительстве особенно чувствуется разница между тем как TS обрабатывает length
у кортежей и у строк шаблонных литералов с известной длиной.
При его строительстве особенно чувствуется разница между тем как TS обрабатывает
length
у кортежей и у строк шаблонных литералов с известной длиной.
Это только запутывает читателя - непонятно, почему нельзя использовать результаты с предыдущей итерации (точнее, частично можно, а частично нет). Длину мы всё равно смотрим у счетчика Count. Соответственно, у конструируемого значения не обязательно должен быть какой-то свой "показатель длины", и неважно, как мы получаем значение на новой итерации. Просто в первом примере мы собирали кортеж и могли смотреть длину прямо у него, поэтому отдельный вспомогательный счетчик был не нужен. А когда делаем строку (или, например, дерево заданной глубины, или ещё что-то), приходится использовать вот этот прием с отдельным счетчиком.
Это только запутывает читателя - непонятно, почему нельзя использовать результаты с предыдущей итерации (точнее, частично можно, а частично нет).
Потому что я выбрал такой алгоритм. Я же это прямым текстом написал:
Само решение - это объединение типов переменных
hexValue1, hexValue2, hexValue3
Если менять алгоритм, тогда и тесты надо поменять для выразительности, но это уже будет реализация другой идеи.
Я не вижу ничего плохого, что бы использовать ваше решение. Но я решил использовать вот такое. Плюс, это позволило несколько раз использовать подход со счетчиками.
Все цель статьи это информация к размышлению. Возможно в другом случае, использование счетчиков позволит упростить алгоритм.
Даже если со стороны посмотреть на это:
Digit | `${Digit}${Digit}` | `${Digit | `${Digit}${Digit}`}${Digit}` | `${Digit | `${Digit}${Digit}` | `${Digit | `${Digit}${Digit}`}${Digit}`}${Digit}`
и вот это:
`${Digit}` | `${Digit}${Digit}` | `${Digit}${Digit}${Digit}` | `${Digit}${Digit}${Digit}${Digit}`
Мой результат выглядит проще для чтения. Но достигнуть его чуть труднее.
Приемы, шаблоны, утилиты Typescript: Циклы, счетчики, шаблоны строк разной длины