fn {{ name }}({{ sig }}) -> {{ ret_ty }} {
    let key = wasm_bindgen::JsValue::from_str("{{ js_name }}");
    let has_method = js_sys::Reflect::has(&self.js_obj, &key).unwrap_or(false);
    if !has_method {
        return {{ default_result_expr }};
    }

    let func_val = match js_sys::Reflect::get(&self.js_obj, &key) {
        Ok(f) => f,
        Err(_) => return {{ default_result_expr }},
    };
    let func: js_sys::Function = match func_val.dyn_into() {
        Ok(f) => f,
        Err(_) => return {{ default_result_expr }},
    };

    let args = js_sys::Array::new();
{% for param in params %}
    args.push(&{{ param }});
{% endfor %}

    let result = func.apply(&self.js_obj, &args);

    match result {
        Err(_) => {{ default_result_expr }},
        Ok(val) => {
            if let Some(s) = val.as_string() {
                match s.as_str() {
{%- for variant in unit_result_variants %}
                    "{{ variant.wire_name }}" => {{ ret_ty }}::{{ variant.name }},
{%- endfor %}
                    _ => {{ unknown_string_result_expr }},
                }
            } else if val.is_object() {
{%- for variant in payload_result_variants %}
                let payload_key_{{ loop.index0 }} = wasm_bindgen::JsValue::from_str("{{ variant.wire_name }}");
                if let Ok(cv) = js_sys::Reflect::get(&val, &payload_key_{{ loop.index0 }}) {
                    if let Some(s) = cv.as_string() {
                        return {{ ret_ty }}::{{ variant.name }}(s);
                    }
                }
{%- endfor %}
                {{ default_result_expr }}
            } else {
                {{ default_result_expr }}
            }
        }
    }
}
