javascript - ¿Cómo defino un tipo de TypeScript con una estructura repetitiva?
Tengo un tipo que se ve algo así:
type Location=`${number},${number};${number},${number};...`
¿Existe un tipo de utilidad como Repeat<T> que pueda hacer esto por mí? algo así:
type Location=Repeat<`${number},${number};`>
Respuesta #1
SOLO FUNCIONA EN TS >=4.5
Es posible crear un tipo independiente.
Por favor, vea este ejemplo:
type Coordinates = `${number},${number};`
type MAXIMUM_ALLOWED_BOUNDARY = 50
type Last<T extends string[]> = T extends [...infer _, infer Last] ? Last : never;
type ConcatPrevious<T extends any[]> = Last<T> extends string ? `${Last<T>}${Coordinates}` : never
type Mapped<
N extends number,
Result extends Array<unknown> = [Coordinates],
> =
(Result['length'] extends N
? Result
: Mapped<N, [...Result, ConcatPrevious<Result>]>
)
// type MyLocation =
// | `${number},${number};`
// | `${number},${number};${number},${number};`
// | `${number},${number};${number},${number};${number},${number};`
// | `${number},${number};${number},${number};${number},${number};${number},${number};`
// | `${number},${number};${number},${number};${number},${number};${number},${number};${number},${number};`
// | ... 44 more ...
// | `${number},${number};${number},${number};${number},${number};${number},${number};${number},${number};${number},${number}; ....
type MyLocation = Mapped<MAXIMUM_ALLOWED_BOUNDARY>[number]
const myLocation1: MyLocation = '45,56;67,68;' // ok
const myLocation2: MyLocation = '45,56;67,68;1,2;3,4;5,6;7,8;9,10;' // ok
const myLocation3: MyLocation = '45,56;67,68;1,2;3,4;5,6;7,8;9,10,' // expected error
Parque infantil
Los tipos Mapped son un tipo de utilidad que representa un bucle while. Itera hasta que la longitud de Result alcance N. En otras palabras, Mapped<10> - iterará 10 veces. Ve este ejemplo en JavaScript puro:
const mapped = (N: number, Result: any[] = []): string => {
if (N === Result.length) {
return Result.join('')
}
const x = Math.random();
const y = Math.random()
return mapped(N, [...Result, `${x},${y};`])
}
Es difícil representar uniones en js, por eso he usado join(''). Espero que esté claro cómo funciona.
Si quieres aumentar MAXIMUM_ALLOWED_BOUNDARY a 500, calentará tu CPU, así que ten cuidado.
Como habrás notado, es imposible en TypeScript representar un patrón recursivo para un tipo, pero es posible crear una unión lo suficientemente grande.
Por favor, tenga en cuenta que hay algunas desventajas del tipo $ {number}. Se le permite usar números con cero a la izquierda como aquí:
const x: `${number}` = '01'.
Enlaces útiles:
Aquí puedes encontrar un ejemplo de cómo puedes crear un rango de números usando este patrón.
Aquí puedes encontrar un PR donde se introdujo esta función
Aquí y aquí puedes encontrar mis artículos que están relacionados con este patrón
Respuesta #2
No creo que haya una manera de definir un patrón repetitivo infinito para un tipo que uses en la declaración de una variable.
Sin embargo, un guardia de tipo en una función puede verificar que una cadena coincida con un patrón infinito, de la siguiente manera (playground):
type MatchesPattern<Pattern extends string, Current extends string> = Current extends `` ? string : (Current extends `${Pattern}${infer Rest}` ? MatchesPattern<Pattern, Rest> : never);
type LocationPattern = `${number},${number};`;
declare function onlyAcceptsLocation<L extends string & IsLocation, IsLocation = MatchesPattern<LocationPattern, L>>(location: L): void;
onlyAcceptsLocation("12,34;56,78;"); // 👍 matches
onlyAcceptsLocation("12,34;56,78"); // ⚠️
onlyAcceptsLocation("12'34;56,78;"); // ⚠️
onlyAcceptsLocation("1,2,3;45,67;"); // ⚠️
