12

I've been having trouble getting jQueryUI work properly. Before I tried to add jQueryUI, having jQuery alone worked just fine.

With the code below, I currently get "TypeError: jQuery is not a function(...)" in chrome, which is strange, considering that jquery is marked as a dependency in the require.config file.

The compiling from .ts to .js happens with no errors.

initApp.ts:

/// <reference path="../../../typings/jqueryui/jqueryui.d.ts"/>
import * as jQuery from "jquery"; //Works completely fine
import * as jQueryUI from "jquery-ui"; //Can't even find the module unless
                                       //d.ts file is modified

Compiled to js:

define(["require", "exports", "jquery-ui"], function (require, exports, jQuery) {...}

jqueryui.d.ts:

/// <reference path="../jquery/jquery.d.ts"/>
declare module JQueryUI { <unmodified code>}

//Added this declare

declare module "jquery-ui" {
  export = jQuery;
}

Require.config.js:

require.config({
    baseUrl: "./components/",
    paths: {
        "jquery": "./javascripts/lib/jquery-2.1.4",
        "jquery-ui": "./javascripts/lib/jquery-ui",
        "go": "./javascripts/lib/go-debug"
    },
    shim: {
        "jquery": {
          exports: "jQuery",
        },
        "jquery-ui": {
            //exports: "jQuery", //Adding this line doesn't fix the problem
            deps: ["jquery"],
        }
    },
});
require(["./javascripts/initApp"]);

Directory Tree:

typings/
    jquery/
        jquery.d.ts
    jqueryui/
        jqueryui.d.ts
web/
    components/
        javascripts/
            lib/
                jquery-2.1.4.js
                jquery-ui.js
                require.js
            initApp.js
            initApp.ts
            require.config.js

Links to full d.ts files:

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/jquery/index.d.ts (jquery V3.3)

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/jqueryui/index.d.ts (QueryUI V1.12)

Any help would be greatly appreciated

1
  • I've removed the solution you had added to your question. This site's editorial practices are such that solutions must be posted as answers so that people can vote on the solution independently from the question. So you should post your solution as an answer. You can go back in the edit history of the question, find the edit where you added the solution, click on the "source" button, copy the source and paste that into the answer form. Should take 2 mins max.
    – Louis
    Commented Feb 28, 2017 at 14:46

4 Answers 4

8

So what happens is that you have jQuery which has an export, and jQueryUi which imports jQuery, augments it, and then exports $.widget not $.

This is why, as I think you already pointed out,

import * as jQuery from 'jquery-ui';

is problematic.

As you go on to note,

import jQueryUi from 'jquery-ui';

Does not work because jQueryUi is never used in a value position and so it gets elided by the compiler, which is actually really useful, if tricky, behavior that can make a number of asynchronous loading scenarios easier.

What you need is a way to tell TypeScript to perform an import of the library regardless of whether or not it is actually used, that is to say, we are importing it for its side effects.

Fortunately, ECMAScript has an import form which is provided specifically for this scenario. By writing

import 'jquery-ui';

you indicate that you depend on 'jquery-ui' for its side effects.

Furthermore, you do not need the shims for jQuery these days (don't quote me on this, my AMD is rusty).

So you should only need the following.

import $ from 'jquery';
// typescript will not remove this as the point of this syntax is: import for side-effects!
import 'jquery-ui';

You should not need to modify your require.config(....), but I could be misreading it.

Also, note the jquery-ui declarations, which you should probably update (your link was dead due to package restructuring) does not declare an exports and references jQuery as a global which sucks and messes up multi-version .d.ts scenarios, but should not make a practical runtime difference in your case.

8
  • When I try import $ from 'jquery' vs. import * as $ from "jquery", I get the error that Module jquery has no default export. Is there another piece I'm missing here? Do I need to edit my import from npmjs.com/package/@types/jqueryui ?
    – azulBonnet
    Commented Jan 11, 2018 at 23:30
  • 1
    @azulBonnet you need to use --allowSyntheticDefaultImports in TypeScript. If that fails, use import $ = require('jquery'); instead, but never ever use import * as $ from 'jquery';. Commented Jan 12, 2018 at 9:33
  • Thank you @Aluan, but it seems I cannot get either to work. With require, I get the warning that require cannot be used when targeting ECMAScript6 or higher. But maybe my tsconfig.json is some entirely different setup: { "compilerOptions": { "outDir": "./wwwroot/build/", "noImplicitAny": false, "noEmitOnError": true, "removeComments": false, "sourceMap": true, "target": "es6", "module": "amd", "moduleResolution": "node", "allowSyntheticDefaultImports": true }, "exclude": [ "node_modules", "wwwroot" ] }
    – azulBonnet
    Commented Jan 16, 2018 at 18:03
  • Then part of your stack is old/broken. --module is not the same as --target anyway. Commented Jan 16, 2018 at 18:04
  • 1
    @AluanHaddad could you elaborate on why import * as $ from 'jquery' should never be used or provide a link? I'm interested in learning more.
    – chili
    Commented Feb 24, 2018 at 8:54
1

I also ran into this problem. After reading several of these questions where the answers were fairly muddled, I came up with the following:

including reference paths at the top of each file will solve this problem. No other changes needed. TS just needs to know where to find the definition files that describes all the functions that are available. Including a direct ref in each file solves that problem:

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

I could not get other methods mentioned to properly resolve. (I presume I am just stupid, but there could be bugs in the code or changing syntax in the APIs) If you have large numbers of files to resolve, this approach might not be the best solution.

0

My initial workaround used to be embedded in the body of my question. I'm reposting it as an answer to meet StackOverflow's editorial guidelines.

Aluan's answer directly answers some of the questions I posed in this block.


I can manually fix the error by editing the compiled javascript to include both "jquery" and "jquery-ui" modules, and assigning them to variables:

define(["require", "exports", "jquery", "jquery-ui"], function (require, exports, jQuery, jQueryUI) {...}

However, I wanted the typescript compiler to automatically do this, or something similar to set both jquery-ui and jquery as dependencies of my file.

TypeScript takes the declared module name and compiles that string into the dependency parameters of the AMD define() function. Therefore, the TypeScript definition d.ts file must declare the module by the same string that represents my library in require.config.js

Simply having an import statement doesn't trigger any action from the TypeScript compiler. Whichever variable (foo, in this case) the properties from the module/library is imported into needs to be called at least once, and cannot conflict with any existing variables in that scope.

Earlier, I used this line:

import * as jQuery from "jquery-ui"

This occupied the 'jQuery' variable name, and thus, the jQuery function was no longer able to be assigned to that variable name, resulging in the error: "jQuery is not a function(...)"

As jquery-ui simply extends jQuery library, I never need call it. But the compiler got too smart on me and decided to not actually compile jquery-ui to be a dependency in my define(...). This was an easy fix once I realized the problem.

Final code


initApp.ts

/// <reference path="../../../typings/jqueryui/jqueryui.d.ts"/>
import * as jQueryUI from "jquery-ui";
import uiVar from "./uiVariables";
jQueryUI

Compiled to js:

define(["require", "exports", "jquery-ui"], function (require, exports, jQueryUI) {...}

require.config.js

require.config({
    baseUrl: "./components/",
    paths: {
        "jquery": "./javascripts/lib/jquery-2.1.4",
        "jquery-ui": "./javascripts/lib/jquery-ui",
        "go": "./javascripts/lib/go-debug"
    }
});
require(["./javascripts/app"]);
1
  • Have you tried import 'jquery-ui';? the import is not removed using module format 'AMD' or any other format for that matter. Commented Mar 2, 2017 at 5:47
0

I produced a little example on GitHub for using TypeScript 2 with ES 6 modules and JQuery / JQuery UI with custom plugins, I hope this will help: https://github.com/lgrignon/typescript-es6-jquery

2
  • Is Babel needed to use Typescript with JQuery and JQueryUI?
    – azulBonnet
    Commented Jan 16, 2018 at 22:36
  • @azulBonnet no it's not Commented Feb 13, 2018 at 19:30

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.