20

I'm rewriting some JS code on TypeScript and encounter with problems with module import. For example, I want to write my toggleVisiblity function. Here is code:

/// <reference path="../../typings/jquery/jquery.d.ts" />

import * as $ from "jquery";

interface JQuery {
    toggleVisibility(): JQuery;
}

$.fn.extend({
    toggleVisibility: function () {
        return this.each(function () {
            const $this = $(this);
            const visibility = $this.css('visibility') === 'hidden' ? 'visible' : 'hidden';
            $this.css('visibility', visibility);
        });
    }
});

const jQuery = $('foo');
const value = jQuery.val();
jQuery.toggleVisibility();

But the problem is that for unknown reason toggleVisibility is not added to JQuery interface thus I get an error Property 'toggleVisibility' does not exist on type 'JQuery'., although it sees other methods (val, each and so on).

Why is it not working?

enter image description here

Paleo
  • 21,831
  • 4
  • 65
  • 76
Alex Zhukovskiy
  • 9,565
  • 11
  • 75
  • 151
  • It seems your interface `JQuery` is not merged with the original one. Maybe it should be imported. How have you imported the definitions for jQuery ? With the new _@types_ system? – Paleo Dec 03 '16 at 17:26
  • @Paleo with `tsd install jQuery --save` afair – Alex Zhukovskiy Dec 03 '16 at 18:10

2 Answers2

36

Try putting the

interface JQuery {
    toggleVisibility(): JQuery;
}

Inside a seperate file without import/export statements. This works for me. Though it wold be interesting to know why.

EDIT: There is an excellent explanation for this behaviour in this answer to post: How to extend the 'Window' typescript interface

Jack Miller
  • 6,843
  • 3
  • 48
  • 66
mode777
  • 3,037
  • 2
  • 23
  • 34
  • I'm going to create an issue in TS github, maybe it will be fixed. Thank you for an answer. – Alex Zhukovskiy Dec 04 '16 at 10:12
  • @AlexZhukovskiy Please give the link to the issue, I'm interested too. – Paleo Dec 05 '16 at 12:34
  • 4
    For those who are struggling to know where to put this file (like myself); this [link](https://www.detroitlabs.com/blog/2018/02/28/adding-custom-type-definitions-to-a-third-party-library/) explains very well. – Mojtaba Feb 13 '19 at 18:11
  • Oh thank goodness I found this post. I was starting to grow gray hairs over documenting this API. – Kris Oye Jul 14 '20 at 20:35
9

I got the solution, this worked for me:

Use the JQueryStatic interface for static jQuery access like $.jGrowl(...) or jQuery.jGrowl(...) or in your case, jQuery.toggleVisibility():

interface JQueryStatic {

    ajaxSettings: any;

    jGrowl(object?, f?): JQuery;

}

And for your own custom made functions you use using jQuery.fn.extend, use the JQuery interface:

interface JQuery {

    fileinput(object?): void;//custom jquery plugin, had no typings

    enable(): JQuery;

    disable(): JQuery;

    check(): JQuery;

    select_custom(): JQuery;

}

Optional, here are my extended JQuery functions:

jQuery.fn.extend({
    disable: function () {
        return this.each(function () {
            this.disabled = true;
        });
    },
    enable: function () {
        return this.each(function () {
            this.disabled = false;
        });
    },
    check: function (checked) {
        if (checked) {
            $(this).parent().addClass('checked');
        } else {
            $(this).parent().removeClass('checked');
        }
        return this.prop('checked', checked);
    },
    select_custom: function (value) {
        $(this).find('.dropdown-menu li').each(function () {
            if ($(this).attr('value') == value) {
                $(this).click();
                return;
            }
        });
    }
});
Displee
  • 670
  • 8
  • 20
  • This approach seems to clobber the `JQuery` declarations for regular functions, like `.click()` and `.parent()`. Any idea why? – Dem Pilafian Jan 19 '21 at 07:31