A simpler recursive version uses array destructuring to test the first value against the target value, adding one if it matches, and zero if it doesn't, then recurring on the remainder of the array. We stop when the value is undefined, meaning we've run out of elements in the array.
const countOcc = (target) => ([x, ...xs]) =>
x == undefined ? 0 : (x == target ? 1 : 0) + countOcc (target) (xs)
const arr = ['a', 'b', 'c', 'a']
console .log (countOcc ('a') (arr))
console .log (countOcc ('b') (arr))
console .log (countOcc ('c') (arr))
console .log (countOcc ('d') (arr))
While we could alter this to make it tail-recursive, current JS engines still do not do tail-call optimization, so it seems a bit pointless. If you were going to do this on large arrays, you would probably need to rewrite with iteration in place of recursion.
I know there is some problem with the return statementwhich return statement? There's no return in a branch of your function++inreturn counter++has no effect. You are before returning the variable and then incrementing it, but since you just exited the function there's no point in incrementing it