Dynamically deciding which operator to use based on the type of the value at hand
So after some helpful comments here and from my colleagues at work I ended up creating functions (with overloading) to solve the issue:
CREATE OR REPLACE FUNCTION contains(haystack jsonb, needle text) RETURNS boolean AS $$
    DECLARE
      result boolean;
    BEGIN
      CASE jsonb_typeof(haystack)
        WHEN 'array', 'object' THEN
          result := haystack ? needle;
        ELSE
          result := haystack LIKE '%' || needle || '%';
      END CASE;
      RETURN result;
    END;
  $$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION contains(haystack text, needle text) RETURNS boolean AS $$
  BEGIN
    RETURN haystack LIKE '%' || needle || '%';
  END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION contains(haystack text[], needle text) RETURNS boolean AS $$
  BEGIN
    RETURN needle = ANY(haystack);
  END;
$$ LANGUAGE plpgsql;

Then I can just include contains(entity.field1, entity.field2) in my query and it works for all three types I need right now. I can also easily extend it to work for more types.
Thanks for all your help