PowerShell's default behavior is to unroll enumerable output, which is why you end up with a "flat" array.
You can circumvent this behavior by using Write-Output -NoEnumerate:
$list1 = 'A','B';
$list2 = '1','2';
$result = foreach ($list1Item in $list1)
{
    foreach ($list2Item in $list2)
    {
        Write-Output ($list1Item, $list2Item) -NoEnumerate
    }
}
Another option is to construct a literal nested array - then the pipeline processor will unroll the first dimension and you're left with array objects:
$list1 = 'A','B';
$list2 = '1','2';
$result = foreach ($list1Item in $list1)
{
    foreach ($list2Item in $list2)
    {
        ,@($list1Item, $list2Item)
      # ^
      # prefixed comma acts as a unary array operator
    }
}
Or you can construct something that isn't enumerable, like an object for each pair:
$list1 = 'A','B';
$list2 = '1','2';
$result = foreach ($list1Item in $list1)
{
    foreach ($list2Item in $list2)
    {
        # this creates a scalar object, nothing to unroll here
        [pscustomobject]@{
          Item1 = $list1Item
          Item2 = $list2Item
        }
    }
}
foreach ($resultItem in $result)
{
    Write-Host "$($resultItem.Item1)-$($resultItem.Item2)"
}
See the about_Pipelines help topic for further discussion on this behavior