On Julia 1.10, the following AbstractVector implementation supports push! and append!:
julia> begin
       struct MyVector <: AbstractVector{Int}
           v::Vector{Int}
           function MyVector(args...)
               new(Vector{Int}(args...))
           end
       end
       Base.size(mv::MyVector) = size(mv.v)
       Base.getindex(v::MyVector, i::Int) = getindex(v.v, i)
       Base.setindex!(mv::MyVector, v, i::Int) = mv.v[i] = v
       Base.resize!(mv::MyVector, nl::Integer) = resize!(mv.v, nl)
       end
julia> v = MyVector(undef, 5)
5-element MyVector:
 0
 0
 0
 0
 0
julia> push!(v, 6)
6-element MyVector:
 0
 0
 0
 0
 0
 6
julia> append!(v, [1,2,3])
9-element MyVector:
 0
 0
 0
 0
 0
 6
 1
 2
 3
Beyond the AbstractArray interface, the only other method needed was resize!. On Julia 1.11, this appears to be no longer the case:
julia> begin
       struct MyVector <: AbstractVector{Int}
           v::Vector{Int}
           function MyVector(args...)
               new(Vector{Int}(args...))
           end
       end
       Base.size(mv::MyVector) = size(mv.v)
       Base.getindex(v::MyVector, i::Int) = getindex(v.v, i)
       Base.setindex!(mv::MyVector, v, i::Int) = mv.v[i] = v
       Base.resize!(mv::MyVector, nl::Integer) = resize!(mv.v, nl)
       end
julia> v = MyVector(undef, 5)
5-element MyVector:
 0
 0
 0
 0
 0
julia> push!(v, 6)
ERROR: MethodError: no method matching sizehint!(::MyVector, ::Int64)
The function `sizehint!` exists, but no method is defined for this combination of argument types.
Closest candidates are:
  sizehint!(::BitSet, ::Integer; first, shrink)
   @ Base bitset.jl:58
  sizehint!(::BitVector, ::Integer)
   @ Base bitarray.jl:809
  sizehint!(::Dict{T}, ::Any; shrink) where T
   @ Base dict.jl:193
  ...
Stacktrace:
 [1] _append!(a::MyVector, ::Base.HasLength, iter::Tuple{Int64})
   @ Base ./array.jl:1320
 [2] append!(a::MyVector, iter::Tuple{Int64})
   @ Base ./array.jl:1313
 [3] push!(a::MyVector, iter::Int64)
   @ Base ./array.jl:1314
 [4] top-level scope
   @ REPL[3]:1
If I follow the suggestion and implement sizehint!, I then get a stack overflow.
julia> Base.sizehint!(v::MyVector, nl::Integer) = sizehint!(v.v, nl)
julia> push!(v, 6)
ERROR: StackOverflowError:
Stacktrace:
      [1] sizehint!(a::Vector{Int64}, sz::Int64; first::Bool, shrink::Bool)
        @ Base ./array.jl:1480
      [2] sizehint!
        @ ./array.jl:1480 [inlined]
      [3] sizehint!
        @ ./REPL[4]:1 [inlined]
      [4] sizehint!
        @ ./array.jl:1519 [inlined]
      [5] _append!
        @ ./array.jl:1320 [inlined]
      [6] append!
        @ ./array.jl:1313 [inlined]
      [7] push!(a::MyVector, iter::Int64)
        @ Base ./array.jl:1314
      [8] _append!
        @ ./array.jl:1322 [inlined]
--- the above 3 lines are repeated 79981 more times ---
 [239952] append!
        @ ./array.jl:1313 [inlined]
The stack overflow is due to push! calling append! which in turn calls push!. This appears to be due to the following pull request that is in Julia 1.11.0-rc2:
I discovered this while I was doing some maintenance on UInt12Arrays.jl, and I noticed that my tests were failing on Julia 1.11.0-rc2. There I noticed that push! and append! no longer work like above. I wonder if this might affect other AbstractArray or AbstractVector implementations.
Perhaps resize! and sizehint! should be added to the AbstractArray interface as an optional method to enable push! and append!.
If we only wanted to depend on resize! for push! and append! to work, perhaps we should consider adding the following to Base:
import Base: push!, sizehint!
function push!(vec::AbstractVector, v)
    new_length = length(vec) + 1
    resize!(vec, new_length)
    vec[new_length] = v
    return vec
end
# do nothing
sizehint!(vec::AbstractVector, nl::Integer) = vec