Ao usar if [ ... ] você está realmente usando o utilitário [ (que é o mesmo que test , mas requer que o último argumento seja ] ).
[ não entende rodar sua função, ela espera strings. Felizmente, você não precisa usar [ aqui (pelo menos para a função):
if [ "$docheck" -eq 1 ] && notContainsElement "$fruit" "${blacklist[@]}"; then
...
fi
Note que eu também estou verificando o inteiro primeiro, para que possamos evitar chamar a função se $docheck não for 1.
Isso funciona porque if recebe um comando arbitrário e decide o que fazer no status de saída desse comando. Aqui, usamos um teste [ ... ] juntamente com uma chamada para sua função, com && intermediário, criando um comando composto. O status de saída do comando composto seria verdadeiro se o [ ... ] test e a função retornassem zero como seus status de saída, sinalizando sucesso.
Como nota de estilo, eu não teria a função testar se a matriz não contém o elemento, mas se contém o elemento e, em seguida,
if [ "$docheck" -eq 1 ] && ! contains "$fruit" "${blacklist[@]}"; then ...
Ter um teste de função um negativo vai atrapalhar a lógica nos casos em que você faz deseja testar se o array contém o elemento ( if ! notContainsElement ... ).