Skip to content

Repetitions

GoogleFeud edited this page Sep 19, 2023 · 2 revisions

ts-macros has repetitions which are heavily inspired by Rust. They allow you to repeat code for every element of an array. Since ts-macros is limited by the typescript compiler, this is the syntax for repetitions:

+[separator?, [arrays], (...params) => codeToRepeat]

The separator is an optional string that will separate all the expressions generated by the repetition. If a separator is omitted, then every expression will be an ExpressionStatement.

[arrays] is an array of array literals. The elements in the arrays are the things the repetition will go through. This is the simplest repetition:

function $test(...numbers: Array<number>) {
    +[[numbers, ["a", "b", "c"]], (num: number|string) => console.log(num)]
}

$test!(1, 2, 3);
console.log(1)
console.log(2)
console.log(3)
console.log("a")
console.log("b")
console.log("c")

The repetition goes through all the numbers and strings and creates a console.log expression for each of them.

Multiple elements in repetition

Let's say you want to go through 2 or more arrays at the same time, to create combinations like 1a, 2b, etc. You can accomplish this by adding another parameter:

function $test(...numbers: Array<number>) {
    +[[numbers, ["a", "b", "c"]], (firstArr: number, secondArr: string) => console.log(firstArr + secondArr)]
}

$test!(1, 2, 3);
console.log("1a")
console.log("2b")
console.log("3c")

The second parameter tells the transformer to separate the second array from the rest. So firstArr goes through all arrays except the second array (["a", "b", "c"]), and in this case, the two arrays just get separated. But what if we add a third array?

function $test(...numbers: Array<number>) {
    +[[numbers, ["a", "b", "c"], ["e", "d", "f"]], (all: number, secondArr: string) => console.log(firstArr + secondArr)]
}

$test!(1, 2, 3);
console.log("1a")
console.log("2b")
console.log("3c")
console.log("e" + null)
console.log("d" + null)
console.log("f" + null)

Here firstArr goes through the first array and the third array, and secondArr goes through the second. The second array only has 3 elements, and so it's null for the elements of the third array.

Separators

You can use the following separators:

  • + - Adds all the values.
  • - - Subtracts all the values.
  • * - Multiplies all the values.
  • . - Creates a property / element access chain from the values.
  • [] - Puts all the values in an array.
  • {} - Creates an object literal from the values. For this separator to work, the result of the repetition callback must be an array literal with 2 elements, the key and the value ([key, value]).
  • () - Creates a comma list expression from all expressions.
  • || - Creates an OR chain with the expressions.
  • && - Creates an AND chain with the expressions.

Repetitions as function arguments

If a repetition is placed inside of a function call, and a separator is not provided, then all results will be passed as arguments.

function $log(...items: Array<number>) {
    console.log(+[[items], (item: number) => item + 1]);
}
$log!(1, 2, 3, 4, 5);
console.log(2, 3, 4, 5, 6);

$$i built-in macro

ts-macros provides a built-in macro, $$i if used inside a repetition, it'll return the number of the current iteration if it's used outside, -1.

import { $$i } from "../../dist";

function $arr(...els: Array<number>) : Array<number> {
    return +["[]", [els], (el: number) => el + $$i!()] as unknown as Array<number>;
}
$arr!(1, 2, 3);
[1, 3, 5]