You can lift the argument to type domain, for example:
struct Foo
x::Int
end
Base.getproperty(foo::Foo, s::Symbol) = bar(foo, Val(s))
bar(foo::Foo, ::Val{T}) where {T} = getfield(foo, T) # fall back to getfield
bar(foo::Foo, ::Val{:y}) = println("Hello, world!")
julia> foo = Foo(4)
Foo(4)
julia> foo.x
4
julia> foo.y
Hello, world!
Edit: Which is what Mauro linked to.