Error: Ajv does not have a construction capability

When attempting to initialize Ajv in my class using the new keyword, I encounter the following error:

TypeError: Ajv is not a constructor

Here's the code snippet:

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())
            }
        }
    }

Upon checking the console log, I found this:

https://i.sstatic.net/MfmEv.png

This implementation previously worked and aligns with how Ajv should be utilized. As per the Ajv documentation:

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);

So, why am I encountering this error?

For reference, here's how the Ajv library is imported - 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'

Answer №1

After noticing that Ajv comes with a default function, I decided to update my code as follows:

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

Although I'm not completely certain about the details, it seems to be functioning correctly now.

Answer №2

This question and answer may be old, but I believe the accepted solution is not optimal and still leaves some questions unanswered. So, here's my take:

The issue at hand is that ajv uses export default or export = syntax, while you are importing using import * as, which brings in an object containing all exports from the ajv module, with the default export accessible via a property called default.

A cleaner way to import the default constructor function would be:

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

instead of

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

If you insist on using import *, then you could do it this way to make Ajv the constructor function instead of Ajv.default:

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

When using require instead of import with a module that uses export default, it behaves like import * as Ajv, meaning you get an object with a default property.

The following methods 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(...); // kind of messy

// 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 need to import the default export along with other exported members without resorting to import * as :

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

In my opinion, the accepted solution has its flaws because if you're only interested in importing the ajv constructor function, it makes more sense to assign it to the Ajv variable rather than the object containing the constructor function as a property named default - and then creating instances with new Ajv.default syntax - which can look confusing.

Answer №3

When I was working on a project that targeted CommonJS using the following tsconfig and corresponding typescript:

{
    "module": "commonjs",
    "moduleResolution": "node",
}
import Validator from 'validator';

const validator = new Validator.default();

However, after updating the project, I encountered an issue where I could no longer use the code above. An error stating

Validator.default is not a constructor
kept popping up. Even trying new Validator() did not work, resulting in a similar typescript-only error. The solution to this problem involved some odd workaround (NOTE: intellisense still functions!):

{
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
}
import ValidatorDefault from 'validator';

const Validator = ValidatorDefault as unknown as typeof ValidatorDefault.default;
const validator = new Validator();

I hope this solution can assist others facing the same issue.

Answer №4

All you need to do is install the ajv package by running "npm install ajv" This will take care of the avj is not a constructor problem for you

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing lodash or underscore libraries, we can compare two objects and eliminate any duplicate entries

Looking at the image below, I have some json data that consists of three objects; each containing a client's id => data. exact_match : {104} match_4 : {104, 103} match_2 : {104, 103, 68} Is there a way to remove duplicate objects based on pre ...

Accessing environment-based constants in TypeScript beyond the scope of Cypress.env()Is there a way to gain access to environment-specific constants

Imagine I have an API test and the URL and Credentials are different between production and development environments: before("Authenticate with auth token", async () => { await spec().post(`${baseUrl}/auth`) .withBody( { ...

Disabling the view picker DIV in MS CRM may not be an available option

I am attempting to disable the view picker feature on the account lookup in 2016. Although my code does not produce any errors, it fails to locate the specific DIV with the ID of "parentaccountid". Upon inspecting the Elements, I can clearly see the "par ...

What is the best method for passing a JavaScript object to PHP using Ajax?

I have looked into similar questions like this and this, but none of them have helped me solve my issue. When I check the console log for my data, it displays the following: Object["row_LM#00000010", "row_LM#00000002", "row_LM#00000009", "row_LM#00000008" ...

Finding the current week using date information from an array of objects in JavaScript

I have an array of objects with a date key, and I am trying to filter out the objects that fall within the current week. How can I achieve this and get the objects from the current week? I attempted to use the filter method, but I believe I need to forma ...

What is the process for indicating an option as "chosen" within Embedded JavaScript Templating (EJS)?

I've been working on a function that allows users to modify each other's data, including the ability to change roles. I'm having trouble getting the select form to display the current role of a user with the "selected" attribute. This is wh ...

Utilizing vanilla JavaScript within a React.js component: A step-by-step guide

I have implemented chartist.js in my React component, and I am facing an issue with displaying the chart on the web page. I am following the example provided at Below is the code snippet: var Chartist = { version:'0.9.5' } (function (wind ...

Struggling to display a collection of items in React

Below is the code snippet : import React, { Component } from 'react'; import axios from 'axios'; import _ from 'lodash'; import Loader from './Loader'; export default class Main extends Component { constructor(p ...

Is there a way to instantiate a new object within the same for loop without replacing the ones created in previous iterations?

My current issue with this exercise is that as I convert the first nested array into an object, the iteration continues to the next nested array and ends up overwriting the object I just created. I'm wondering how I can instruct my code to stop itera ...

Use regular expressions to split a number string based on the individual digit values

Is it possible to use regex to split a string that consists only of numbers based on matching digit values? Take for instance this input: "11222344" The expected output should be: ["11","222","3","44"] ...

Error deploying to Heroku: Unable to obtain access

I've been working on deploying my MEAN application to Heroku, and while the deployment is successful, I'm encountering an error when trying to open the application - it keeps showing a "CANNOT / GET" message. Upon checking the console, I see the ...

Ionic2: expanding menu options in the sidemenu

I'm not very familiar with ionic, but I have a question on behalf of my friend who is hesitant to ask on StackOverflow because she's unsure of how to frame her question. She simply wants to learn how to implement a submenu in an ionic 2 side men ...

What is the best method to retrieve an Element using both its ID and value?

Is there a way to disable specific radio buttons based on both their id and value attributes? I have three radio buttons that need to be disabled. <input id="selectedAnswerIDforQ15" name="selectedAnswerIDforQ15" type="radio" value="78" /> <input ...

Issue with Durandal dialog repositioning failing to function

I've been attempting to adjust the positioning of a Durandal dialog, but have been unsuccessful so far. The code snippet I'm using is as follows: this.compositionComplete = function (child, parent, context) { dialog.getContext().reposition(c ...

Show and hide the responsive menu with a single click

I am currently working on creating a responsive menu. It is functioning properly, however, I am having trouble implementing an onclick effect in CSS. At the moment, I am using a hover effect. How can I make it so that when the screen width is less than 750 ...

Performing simultaneous updates to multiple records using CAML/jQuery in Sharepoint (Batch updates)

I am working on updating multiple records in Share Point using jQuery and CAML queries. While it's easy to update a single record with the current code, I need to handle 20 Products simultaneously for this particular project. Instead of looping throug ...

Disabling eslint does not prevent errors from occurring for the unicorn/filename-case rule

I have a file called payment-shipping.tsx and eslint is throwing an error Filename is not in camel case. Rename it to 'paymentShipping.tsx' unicorn/filename-case However, the file needs to be in kebab case since it's a next.js page that s ...

The Javascript Keydown event seems to fire twice

When the user presses ctrl + z, I want to trigger an undo action by handling a keydown event on the document. This is how I have set up the event listener in my document: componentWillMount() { window.addEventListener('keydown', throttle(this ...

Typescript encounters Duplicate error when method overloading is implemented

Below is the code snippet that I am working with: public async insert(data: iFlower | iFlower[]): Promise<iFlower> | Promise<iFlower[]> { await this.insert(data); } private async insert(data: iFlower): Promise<iFlower>{ .... return d ...

Accessing external data in Angular outside of a subscription method for an observable

I am struggling to access data outside of my method using .subscribe This is the Service code that is functioning correctly: getSessionTracker(): Observable<ISessionTracker[]> { return this.http.get(this._url) .map((res: Response) => ...