How to cast as ArrayList, preset data in param block, and return as ArrayList?

Explicit parameter type casting

The second example you posted (explicitly casting the parameter variable) is the correct way to go:

Function Test-Me {
    Param(
        [System.Collections.ArrayList]
        $Properties = @("red","blue","green")
    )

    Write-Host $Properties.GetType().FullName

    if("Orange" -notin $Properties){
        [void]$Properties.Add("orange")
    }

    $Properties
}

Resulting in:

PS C:\> Test-Me
System.Collections.ArrayList
red
blue
green
orange

PS C:\> Test-Me -Properties "one","two","three"
System.Collections.ArrayList
one
two
three
orange

OutputType

One thing that surprised me though, is that even with the [OutputType] attribute, the function outputs a regular array (this may actually be a bug intended behavior, see update below):

Function Test-Me {
    [OutputType([System.Collections.ArrayList])]
    Param(
        [System.Collections.ArrayList]
        $Properties = @("red","blue","green")
    )
    
    if("Orange" -notin $Properties){
        [void]$Properties.Add("orange")
    }

    $Properties
}

Still resulting in a regular object array being returned:

PS C:\> (Test-Me).GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

Update (with easy workaround)

As demonstrated in the comment on your Connect bug submission, PowerShell deliberately enumerates the items of any enumerable output in order to provide a consistent behavior for the pipeline (pseudo-C# stolen from commentor Derp McDerp on Connect):

if (returned_value is IEnumerable) {
    foreach (r in returned_value) {
        yield r;
    }
} else {
    yield returned_value;
}

The trick is then to wrap the collection in a single-item array, causing PowerShell to pipe it as a single item (notice to , before $Properties):

Function Test-Me {
    [OutputType([System.Collections.ArrayList])]
    Param(
        [System.Collections.ArrayList]
        $Properties = @("red","blue","green")
    )
    
    if("Orange" -notin $Properties){
        [void]$Properties.Add("orange")
    }

    ,$Properties
}

and now, we get an output with the correct type:

PS C:\> (Test-Me).GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     ArrayList                                System.Object