Don’t get me wrong, the possibility of better error messages, compile-time errors, and (perhaps - because that can be solved with good documentation) more readable code is the advantage of static typing.
But in Julia that is not as natural, and not doing it has its own benefits, even for code quality. You can use all the Julia functions because most of them are type-generic. In terms of code debugging, for example, I have a package in which I was interested in 3D particles, of coordinates of represented by floats. Not even 32bit floats interested me. I was very used to type-typing everything (from Fortran). But then I found out that relaxing that allowed my code to run with 2D particles, coordinates with units, automatic differentiation, etc. Each of these things had a tremendous impact on what I can do to debug my code, which was for me much better than simply knowing that a variable got into the right place with the correct type, which is a much more simple error that the thing I can inspect by visualizing 2D representations of the system or computing automatic derivatives, propagating units, etc.
Concerning this specific situation, if you want to throw an error at the function call, for a function given by the user, you could wrap it in another function and assert the type of the input:
ulia> function f(g,x)
@assert x isa Integer "x must be integer"
f (generic function with 1 method)
julia> g(x) = x^2
g (generic function with 1 method)
ERROR: AssertionError: x must be integer
Not that this is better in general, but can be useful for the cases where you want to provide a better error message for a user that passes a function to your code.