I would recommend the wrapper-function approach. There’s two downsides to skipping it that I can think of:
Exposing the recursive variant means you have to do argument validation on every recursion, which might be wasteful, depending on the kind of validation you need.
fib isn’t defined for negative numbers. Ideally, you would have an “entry point” public function which can check for the negative once, and then call off to a private recursive function which can just safely assume the input is non-negative.
Leaking implementation details
A lot of recursive function have parameters that exist only for the sake of supporting the recursion. Typically, your public “entry point” function will pre-populate these with appropriate values for the start of the recursion. If you didn’t have that, your parameters will be visible to the rest of the world. Default parameters can help with this, but the existence of these still parameters still leak, and it clutters your API.
Consider also that this prevents you from being able to change the implementation in the future. For example, if you had a function that recursively reverses a linked list, you would benefit from having an
accumulator parameter that helps you be able to take advantage of Tail Call Optimization. If you then decided to switch to an iterative approach, you can’t remove your
accumulator parameter, because that would be breaking your public API.