Nitzan Tomer Nitzan Tomer - 1 year ago 102
TypeScript Question

importing goes wrong with systemjs

I'm trying to use an existing js library (validate.js) in both the client and server.

I installed it using npm, and everything compiles for both server and client.

When using it in the server it works great, but when I execute it in the browser it throws an error.

The same file is used in both cases:

import validate = require("validate.js");

export function RequestValidator(data: any): any {
return (validate as any)(data, constraints, { allowEmpty: true });

is asserted to
becuase otherwise I get:

TS2349: Cannot invoke an expression whose type lacks a call signature.

I'm using is:

declare module "validate.js" {
export interface ValidateJS {
(attributes: any, constraints: any, options?: any): any;
async(attributes: any, constraints: any, options?: any): Promise<any>;
single(value: any, constraints: any, options?: any): any;

export const validate: ValidateJS;
export default validate;

The module only exports a function, and that works well in the server, but in the client when invoking this function I get:

Uncaught TypeError: validate is not a function(…)

The code is compiled using target
for the server:

"use strict";
const validate = require("validate.js");

for the client:

System.register(["validate.js"], function(exports_1, context_1) {
"use strict";
var __moduleName = context_1 &&;
var validate;

return {
function (validate_1) {
validate = validate_1;

When debugging it,
indeed isn't a function it's:

validate: r
get EMPTY_STRING_REGEXP: function()
set EMPTY_STRING_REGEXP: function()
Promise: (...)
get Promise: function()
set Promise: function()
__useDefault: (...)
get __useDefault: function()
set __useDefault: function()
async: (...)
get async: function()
set async: function()
capitalize: (...)
get capitalize: function()
set capitalize: function()
cleanAttributes: (...)
get cleanAttributes: function()
set cleanAttributes: function()

Any idea what's going on and why it behaves this way in the browser?

Answer Source

When you compile with "module": "system", node-compatible import

import validate = require("validate.js");

no longer works - the value you are getting for validate is a module, not a function. This may be a bug in typescript, or it could be by design - I don't know. (update: from github comment addressed to JsonFreeman here, it looks like it's by design: you get the module object with a set of properties including one named default).

There are several ways around this.

First, you can do easy conversion yourself - the function that you need is provided as default property of the module, so this line will fix it:

validate = validate.default ? validate.default : validate;

Or, you can compile with "module": "commonjs" even for the browser, so typescript will generate working code, and systemjs will detect format for your modules automatically.

Or finally, you could still compile with "module": "system", but import validate.js as it's intended in its typings:

import validate from 'validate.js';

That way you don't have to do any casts to any, and typescript will generate necessary access for default property, but the drawback is that it will not work at all in node when imported that way.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download