```ts
/**
 * Splits an array into consecutive groups of at most `size` elements.
 * The last group is shorter if the length does not divide evenly.
 * The input array must not be mutated.
 * @param items Array of T to split into chunks.
 * @param size Number of elements per chunk.
 * @returns An array where each element is a chunk of size T.
 */
export function chunk<T>(items: readonly T[], size: number): T[][] {
  if (!size || size < 1) throw new Error('Size must be a positive integer');

  const results: T[][] = [];
  for (let i = 0; i < items.length; i += size) {
    if (i + size <= items.length) results.push(items.slice(i, i + size));
    else results.push(items.slice(i));
  }
  return results;
}
```