TypeError: Ajv is not a constructor
Asked Answered
J

4

12

I have this class where I try to instantiate Ajv with the new keyword and I get this error:

TypeError: Ajv is not a constructor

Code:

import * as Ajv from "ajv";

    export class ValidateJsonService {
        validateJson(json, schema) {
            console.log(Ajv);
            let ajv = new Ajv({ allErrors: true });
            if (!ajv.validate(schema, json)) {
                throw new Error("JSON does not conform to schema: " + ajv.errorsText())
            }
        }
    }

The console log:

enter image description here

This code used to be working and it is how Ajv is used. From the Ajv docs:

The fastest validation call:

var Ajv = require('ajv');
var ajv = new Ajv(); // options can be passed, e.g. {allErrors: true}
var validate = ajv.compile(schema);
var valid = validate(data);
if (!valid) console.log(validate.errors);

How come I'm getting this error?

See the bottom of this for how I import the Ajv library - systemjs.config.js:

(function (global) {
    System.config({
        paths: {
            // paths serve as alias
            'npm:': 'lib/js/'
        },
        // map tells the System loader where to look for things
        map: {
            app: 'app', 
            // angular bundles
            '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
            '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
            '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
            '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
            '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
            '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
            '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
            '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
            // other libraries
            'rxjs': 'npm:rxjs',
            'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api',
            'angular2-google-maps/core': 'npm:angular2-google-maps/core/core.umd.js',
            'ajv': 'npm:ajv/dist/ajv.min.js',
            'primeng': 'npm:primeng'
Jawbone answered 8/2, 2017 at 1:54 Comment(5)
import Ajv from 'ajv'Tauten
@Tauten I went with this in the end.Jawbone
@Jawbone Do you know where should i change it ``let ajv = new Ajv.default({ allErrors: true });```I mean is it under node_modules > ajv > lib ?Globefish
@Globefish no, not in node_modules. In your own code where you want to use Ajv. It will replace this line in my question: let ajv = new Ajv({ allErrors: true }); and var ajv = new Ajv(); // options can be passed, e.g. {allErrors: true}. It is just creating a new instance of Ajv to then use.Jawbone
Sorry I am not using AJV in my code...i haven't used that oneGlobefish
J
13

I saw that Ajv has a default function so I changed my code to this:

let ajv = new Ajv.default({ allErrors: true });

Not 100% sure what is going on there but it works.

Jawbone answered 8/2, 2017 at 23:42 Comment(2)
for me let ajv = new Ajv({ allErrors: true }); worked today.Abhor
As per the documentation (ajv.js.org/guide/getting-started.html#basic-data-validation) you could also have: const Ajv = require('ajv').default; const ajv = new Ajv();Bybee
M
2

Old question and old answer, but since I think the accepted answer isn't ideal and also leaves unanswered questions, I'm still adding my $.02:

What's causing this is that ajv uses export default or export = syntax, and you're using import * as which imports an object with all exported members from the ajv module, where the default export is a property called default.

The most reasonable way to import the default constructor function is to use:

import Ajv from 'ajv';
const ajv = new Ajv(...);

rather than

import * as Ajv from 'ajv';
const ajv = new Ajv.default(...); // Ajv is an object containing _all_ exports from the ajv module

If you absolutely feel that you must use import *, then this would at least be cleaner, so that Ajv rather than Ajv.default is the constructor function:

import * as AjvModule from 'ajv';
const {default: Ajv} = AjvModule;

If using require rather than import to access exported members from a module that uses export default, it will behave like import * as Ajv, i.e., you will get an object with a default property in it.

So the following are equivalent:

// Pre-ES6 require
const Ajv = require('ajv').default;
const ajv = new Ajv(...);

// Import default
import Ajv from 'ajv';
const ajv = new Ajv(...);

// Import entire module and use default property
import * as Ajv from 'ajv';
const ajv = new Ajv.default(...); // just ugly!

// Import entire module as AjvModule and assign constructor function to Ajv
import * as AjvModule from 'ajv';
const {default: Ajv} = AjvModule;
const ajv = new Ajv(...);

If you do need to import the default export and additional exported members, you can do that without resorting to import * as :

import Ajv, {EnumParams} from 'ajv';
const ajv = new Ajv(...);

Personally I think the accepted answer is somewhat flawed because if you're only interested in importing the ajv constructor function, it makes sense to assign it to the Ajv variable rather than the object that contains the constructor function as a property called default - and then create classes with new Ajv.default syntax - that just looks strange.

Micaelamicah answered 25/2, 2021 at 10:33 Comment(1)
ONLY the accepted answer works for me in Nodejs, but not with webpack. In webpack, ONLY your answer works, import Ajv from 'ajv', using ajv 7.2.1.Protolanguage
L
2

I was previously using AJV on a project that was targeting CommonJS with this tsconfig and corresponding typescript:

{
    "module": "commonjs",
    "moduleResolution": "node",
}
import Ajv from 'ajv';

const ajv = new Ajv.default();

But after updating our project I was not able to use the above. I started getting an error that Ajv.default is not a constructor. Trying to use new Ajv() did not work either... with a similar typescript-only error. The solution was to do this sillyness (NOTE: the intellisense still works!):

{
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
}
import AjvDefault from 'avj';

const Ajv = AjvDefault as unknown as typeof AjvDefault.default;
const ajv = new Ajv();

I really hope this helps someone.

Liard answered 4/10, 2023 at 8:7 Comment(0)
B
-4

Simply you don't have to do anything, just install ajv package "npm install ajv" it will resolve avj is not a constructor issue

Bendigo answered 3/10, 2022 at 3:31 Comment(1)
This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From ReviewMadcap

© 2022 - 2024 — McMap. All rights reserved.